Commit 4e2e48ba authored by mergify[bot]'s avatar mergify[bot] Committed by GitHub

Merge branch 'develop' into felipe/ufm

parents 0d0fd511 a88cd430
---
'@eth-optimism/chain-mon': patch
---
Update import path for artifact
---
'@eth-optimism/contracts-bedrock': minor
---
Migrate contracts periphery into bedrock
...@@ -72,12 +72,12 @@ jobs: ...@@ -72,12 +72,12 @@ jobs:
command: mkdir -p /tmp/test-results command: mkdir -p /tmp/test-results
- run: - run:
name: build Cannon example binaries name: build Cannon example binaries
command: make elf # only compile ELF binaries with Go, we do not have MIPS GCC for creating the debug-dumps. command: make elf # only compile ELF binaries with Go, we do not have MIPS GCC for creating the debug-dumps.
working_directory: cannon/example working_directory: cannon/example
- run: - run:
name: Cannon Go lint name: Cannon Go lint
command: | command: |
golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint --timeout 5m -e "errors.As" -e "errors.Is" ./... make lint
working_directory: cannon working_directory: cannon
- run: - run:
name: Cannon Go tests name: Cannon Go tests
...@@ -90,6 +90,18 @@ jobs: ...@@ -90,6 +90,18 @@ jobs:
command: codecov --verbose --clean --flags cannon-go-tests command: codecov --verbose --clean --flags cannon-go-tests
- store_test_results: - store_test_results:
path: /tmp/test-results path: /tmp/test-results
cannon-build-test-vectors:
docker:
- image: us-docker.pkg.dev/oplabs-tools-artifacts/images/ci-builder:latest
resource_class: medium
steps:
- checkout
- check-changed:
patterns: cannon/mipsevm/open_mips_tests/test
- run:
name: Build MIPS test vectors
command: python3 maketests.py && git diff --exit-code
working_directory: cannon/mipsevm/open_mips_tests
pnpm-monorepo: pnpm-monorepo:
docker: docker:
...@@ -103,10 +115,19 @@ jobs: ...@@ -103,10 +115,19 @@ jobs:
name: Restore PNPM Package Cache name: Restore PNPM Package Cache
keys: keys:
- pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }} - pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }}
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
- run: - run:
name: Install dependencies name: Install dependencies
command: pnpm install --frozen-lockfile command: pnpm install --frozen-lockfile
...@@ -118,10 +139,8 @@ jobs: ...@@ -118,10 +139,8 @@ jobs:
- "packages/chain-mon/node_modules" - "packages/chain-mon/node_modules"
- "packages/common-ts/node_modules" - "packages/common-ts/node_modules"
- "packages/contracts-bedrock/node_modules" - "packages/contracts-bedrock/node_modules"
- "packages/contracts-periphery/node_modules"
- "packages/core-utils/node_modules" - "packages/core-utils/node_modules"
- "packages/fault-detector/node_modules" - "packages/fault-detector/node_modules"
- "packages/hardhat-deploy-config/node_modules"
- "packages/replica-healthcheck/node_modules" - "packages/replica-healthcheck/node_modules"
- "packages/sdk/node_modules" - "packages/sdk/node_modules"
- run: - run:
...@@ -322,11 +341,20 @@ jobs: ...@@ -322,11 +341,20 @@ jobs:
keys: keys:
- pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }} - pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }}
- check-changed: - check-changed:
patterns: contracts-bedrock,hardhat-deploy-config patterns: contracts-bedrock
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
- run: - run:
name: print forge version name: print forge version
command: forge --version command: forge --version
...@@ -356,11 +384,20 @@ jobs: ...@@ -356,11 +384,20 @@ jobs:
keys: keys:
- pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }} - pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }}
- check-changed: - check-changed:
patterns: contracts-bedrock,hardhat-deploy-config patterns: contracts-bedrock
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
- run: - run:
name: print forge version name: print forge version
command: forge --version command: forge --version
...@@ -383,11 +420,20 @@ jobs: ...@@ -383,11 +420,20 @@ jobs:
keys: keys:
- pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }} - pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }}
- check-changed: - check-changed:
patterns: contracts-bedrock,hardhat-deploy-config patterns: contracts-bedrock
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
- run: - run:
name: lint name: lint
command: | command: |
...@@ -459,11 +505,20 @@ jobs: ...@@ -459,11 +505,20 @@ jobs:
keys: keys:
- pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }} - pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }}
- check-changed: - check-changed:
patterns: contracts-bedrock,hardhat-deploy-config patterns: contracts-bedrock
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
- run: - run:
name: slither name: slither
command: | command: |
...@@ -484,11 +539,20 @@ jobs: ...@@ -484,11 +539,20 @@ jobs:
keys: keys:
- pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }} - pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }}
- check-changed: - check-changed:
patterns: contracts-bedrock,hardhat-deploy-config patterns: contracts-bedrock
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
- run: - run:
name: validate spacers name: validate spacers
command: pnpm validate-spacers command: pnpm validate-spacers
...@@ -502,10 +566,19 @@ jobs: ...@@ -502,10 +566,19 @@ jobs:
- attach_workspace: { at: "." } - attach_workspace: { at: "." }
- check-changed: - check-changed:
patterns: contracts-bedrock,contracts patterns: contracts-bedrock,contracts
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
- run: - run:
name: Compile with metadata hash name: Compile with metadata hash
command: pnpm clean && pnpm build:with-metadata command: pnpm clean && pnpm build:with-metadata
...@@ -537,10 +610,19 @@ jobs: ...@@ -537,10 +610,19 @@ jobs:
- pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }} - pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }}
- check-changed: - check-changed:
patterns: contracts-bedrock,contracts patterns: contracts-bedrock,contracts
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
- run: - run:
name: Echidna Fuzz <<parameters.echidna_target>> name: Echidna Fuzz <<parameters.echidna_target>>
command: pnpm echidna:<<parameters.echidna_target>> command: pnpm echidna:<<parameters.echidna_target>>
...@@ -560,10 +642,19 @@ jobs: ...@@ -560,10 +642,19 @@ jobs:
- pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }} - pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }}
- check-changed: - check-changed:
patterns: contracts-bedrock,op-bindings patterns: contracts-bedrock,op-bindings
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
- run: - run:
name: check go bindings name: check go bindings
command: make && git diff --exit-code command: make && git diff --exit-code
...@@ -593,10 +684,19 @@ jobs: ...@@ -593,10 +684,19 @@ jobs:
- pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }} - pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }}
- check-changed: - check-changed:
patterns: <<parameters.package_name>>,<<parameters.dependencies>> patterns: <<parameters.package_name>>,<<parameters.dependencies>>
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
- run: - run:
name: Lint name: Lint
command: pnpm lint && git diff --exit-code command: pnpm lint && git diff --exit-code
...@@ -666,10 +766,19 @@ jobs: ...@@ -666,10 +766,19 @@ jobs:
- checkout - checkout
- check-changed: - check-changed:
patterns: specs/(.*)\.md$ patterns: specs/(.*)\.md$
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
- run: - run:
name: pnpm dev deps name: pnpm dev deps
command: pnpm install command: pnpm install
...@@ -685,6 +794,7 @@ jobs: ...@@ -685,6 +794,7 @@ jobs:
image: ubuntu-2204:2022.07.1 image: ubuntu-2204:2022.07.1
steps: steps:
- checkout - checkout
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
...@@ -742,20 +852,25 @@ jobs: ...@@ -742,20 +852,25 @@ jobs:
- pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }} - pnpm-packages-v2-{{ checksum "pnpm-lock.yaml" }}
- check-changed: - check-changed:
patterns: packages patterns: packages
# TODO remove me after ci builder updated
- run: - run:
name: Install pnpm package manager name: Install pnpm package manager
command: | command: |
npm i pnpm --global npm i pnpm --global
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install yarn package manager
command: |
npm i yarn@1 --global
# Note: The below needs to be manually configured whenever we # Note: The below needs to be manually configured whenever we
# add a new package to CI. # add a new package to CI.
- run: - run:
name: Check common-ts name: Check common-ts
command: npx depcheck command: npx depcheck
working_directory: packages/common-ts working_directory: packages/common-ts
- run:
name: Check contracts-periphery
command: npx depcheck
working_directory: packages/contracts-periphery
- run: - run:
name: Check core-utils name: Check core-utils
command: npx depcheck command: npx depcheck
...@@ -909,15 +1024,32 @@ jobs: ...@@ -909,15 +1024,32 @@ jobs:
source $HOME/.bashrc source $HOME/.bashrc
foundryup foundryup
echo 'export PATH=$HOME/.foundry/bin:$PATH' >> $BASH_ENV echo 'export PATH=$HOME/.foundry/bin:$PATH' >> $BASH_ENV
source $HOME/.bashrc
forge --version
- run: - run:
name: Install pnpm package manager name: Install NVM
command: |
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
source ~/.bashrc
nvm --version
- run:
name: Install Node
command: |
nvm install
nvm use && node --version && npm --version
# TODO remove me after ci builder updated
# A github dep clones-with-immutable-args is installed via github
# packages installed via npm via github automatically run postpack scripts
# their postpack script happens to use yarn so we need it here
- run:
name: Install Package managers
command: | command: |
npm i pnpm --global npm i pnpm --global
npm i yarn@1 --global
- run: - run:
name: Install and build name: Install and build
command: | command: |
pnpm install pnpm install && pnpm build
pnpm build
- when: - when:
condition: condition:
and: and:
...@@ -1190,32 +1322,25 @@ workflows: ...@@ -1190,32 +1322,25 @@ workflows:
- op-bindings-build: - op-bindings-build:
requires: requires:
- pnpm-monorepo - pnpm-monorepo
- js-lint-test:
name: contracts-periphery-tests
coverage_flag: contracts-periphery-tests
package_name: contracts-periphery
dependencies: "(contracts|contracts-bedrock|core-utils|hardhat-deploy-config)"
requires:
- pnpm-monorepo
- js-lint-test: - js-lint-test:
name: chain-mon-tests name: chain-mon-tests
coverage_flag: chain-mon-tests coverage_flag: chain-mon-tests
package_name: chain-mon package_name: chain-mon
dependencies: "(common-ts|contracts-periphery|core-utils|sdk)" dependencies: "(common-ts|contracts-bedrock|core-utils|sdk)"
requires: requires:
- pnpm-monorepo - pnpm-monorepo
- js-lint-test: - js-lint-test:
name: fault-detector-tests name: fault-detector-tests
coverage_flag: fault-detector-tests coverage_flag: fault-detector-tests
package_name: fault-detector package_name: fault-detector
dependencies: '(common-ts|core-utils|sdk)' dependencies: "(common-ts|core-utils|sdk)"
requires: requires:
- pnpm-monorepo - pnpm-monorepo
- js-lint-test: - js-lint-test:
name: sdk-next-tests name: sdk-next-tests
coverage_flag: sdk-next-tests coverage_flag: sdk-next-tests
package_name: sdk package_name: sdk
dependencies: '(common-ts|contracts-bedrock|core-utils)' dependencies: "(common-ts|contracts-bedrock|core-utils)"
requires: requires:
- pnpm-monorepo - pnpm-monorepo
- js-lint-test: - js-lint-test:
...@@ -1229,7 +1354,7 @@ workflows: ...@@ -1229,7 +1354,7 @@ workflows:
name: sdk-tests name: sdk-tests
coverage_flag: sdk-tests coverage_flag: sdk-tests
package_name: sdk package_name: sdk
dependencies: '(contracts-bedrock|core-utils)' dependencies: "(contracts-bedrock|core-utils)"
requires: requires:
- pnpm-monorepo - pnpm-monorepo
- depcheck: - depcheck:
...@@ -1489,6 +1614,7 @@ workflows: ...@@ -1489,6 +1614,7 @@ workflows:
- check-generated-mocks-op-node - check-generated-mocks-op-node
- check-generated-mocks-op-service - check-generated-mocks-op-service
- cannon-go-lint-and-test - cannon-go-lint-and-test
- cannon-build-test-vectors
release: release:
jobs: jobs:
- hold: - hold:
...@@ -1646,7 +1772,7 @@ workflows: ...@@ -1646,7 +1772,7 @@ workflows:
cron: "0 0,6,12,18 * * *" cron: "0 0,6,12,18 * * *"
filters: filters:
branches: branches:
only: [ "develop" ] only: ["develop"]
jobs: jobs:
- fpp-verify: - fpp-verify:
context: context:
...@@ -1660,7 +1786,7 @@ workflows: ...@@ -1660,7 +1786,7 @@ workflows:
cron: "0 0 * * *" cron: "0 0 * * *"
filters: filters:
branches: branches:
only: [ "develop" ] only: ["develop"]
jobs: jobs:
- bedrock-markdown-links: - bedrock-markdown-links:
context: slack context: slack
...@@ -2,11 +2,9 @@ ...@@ -2,11 +2,9 @@
/packages/common-ts @ethereum-optimism/typescript-reviewers /packages/common-ts @ethereum-optimism/typescript-reviewers
/packages/contracts @ethereum-optimism/contract-reviewers /packages/contracts @ethereum-optimism/contract-reviewers
/packages/contracts-bedrock @ethereum-optimism/contract-reviewers /packages/contracts-bedrock @ethereum-optimism/contract-reviewers
/packages/contracts-periphery @ethereum-optimism/contract-reviewers
/packages/core-utils @ethereum-optimism/legacy-reviewers /packages/core-utils @ethereum-optimism/legacy-reviewers
/packages/chain-mon @smartcontracts /packages/chain-mon @smartcontracts
/packages/fault-detector @ethereum-optimism/devxpod /packages/fault-detector @ethereum-optimism/devxpod
/packages/hardhat-deploy-config @ethereum-optimism/legacy-reviewers
/packages/replica-healthcheck @ethereum-optimism/legacy-reviewers /packages/replica-healthcheck @ethereum-optimism/legacy-reviewers
/packages/sdk @ethereum-optimism/devxpod /packages/sdk @ethereum-optimism/devxpod
/packages/atst @ethereum-optimism/devxpod /packages/atst @ethereum-optimism/devxpod
......
...@@ -17,11 +17,6 @@ dist ...@@ -17,11 +17,6 @@ dist
artifacts artifacts
cache cache
packages/contracts-periphery/coverage*
packages/contracts-periphery/@openzeppelin*
packages/contracts-periphery/hardhat*
packages/contracts-periphery/forge-artifacts*
packages/contracts-bedrock/deployments/devnetL1 packages/contracts-bedrock/deployments/devnetL1
packages/contracts-bedrock/deployments/anvil packages/contracts-bedrock/deployments/anvil
......
[submodule "packages/contracts-periphery/lib/multicall"]
path = packages/contracts-periphery/lib/multicall
url = https://github.com/mds1/multicall
[submodule "lib/multicall"]
branch = v3.1.0
...@@ -16,10 +16,6 @@ ...@@ -16,10 +16,6 @@
"directory": "packages/contracts", "directory": "packages/contracts",
"changeProcessCWD": true "changeProcessCWD": true
}, },
{
"directory": "packages/contracts-periphery",
"changeProcessCWD": true
},
{ {
"directory": "packages/chain-mon", "directory": "packages/chain-mon",
"changeProcessCWD": true "changeProcessCWD": true
......
...@@ -52,7 +52,6 @@ Refer to the Directory Structure section below to understand which packages are ...@@ -52,7 +52,6 @@ Refer to the Directory Structure section below to understand which packages are
├── <a href="./packages">packages</a> ├── <a href="./packages">packages</a>
│ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript │ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript
│ ├── <a href="./packages/contracts-bedrock">contracts-bedrock</a>: Bedrock smart contracts. │ ├── <a href="./packages/contracts-bedrock">contracts-bedrock</a>: Bedrock smart contracts.
│ ├── <a href="./packages/contracts-periphery">contracts-periphery</a>: Peripheral contracts for Optimism
│ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier │ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier
│ ├── <a href="./packages/chain-mon">chain-mon</a>: Chain monitoring services │ ├── <a href="./packages/chain-mon">chain-mon</a>: Chain monitoring services
│ ├── <a href="./packages/fault-detector">fault-detector</a>: Service for detecting Sequencer faults │ ├── <a href="./packages/fault-detector">fault-detector</a>: Service for detecting Sequencer faults
...@@ -79,7 +78,6 @@ Refer to the Directory Structure section below to understand which packages are ...@@ -79,7 +78,6 @@ Refer to the Directory Structure section below to understand which packages are
~~ Pre-BEDROCK ~~ ~~ Pre-BEDROCK ~~
├── <a href="./packages">packages</a> ├── <a href="./packages">packages</a>
│ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript │ ├── <a href="./packages/common-ts">common-ts</a>: Common tools for building apps in TypeScript
│ ├── <a href="./packages/contracts-periphery">contracts-periphery</a>: Peripheral contracts for Optimism
│ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier │ ├── <a href="./packages/core-utils">core-utils</a>: Low-level utilities that make building Optimism easier
│ ├── <a href="./packages/chain-mon">chain-mon</a>: Chain monitoring services │ ├── <a href="./packages/chain-mon">chain-mon</a>: Chain monitoring services
│ ├── <a href="./packages/fault-detector">fault-detector</a>: Service for detecting Sequencer faults │ ├── <a href="./packages/fault-detector">fault-detector</a>: Service for detecting Sequencer faults
......
...@@ -11,3 +11,4 @@ state.json ...@@ -11,3 +11,4 @@ state.json
*.json *.json
*.pprof *.pprof
*.out *.out
bin
GITCOMMIT := $(shell git rev-parse HEAD)
GITDATE := $(shell git show -s --format='%ct')
VERSION := v0.0.0
LDFLAGSSTRING +=-X main.GitCommit=$(GITCOMMIT)
LDFLAGSSTRING +=-X main.GitDate=$(GITDATE)
LDFLAGSSTRING +=-X github.com/ethereum-optimism/optimism/op-program/version.Version=$(VERSION)
LDFLAGSSTRING +=-X github.com/ethereum-optimism/optimism/op-program/version.Meta=$(VERSION_META)
LDFLAGS := -ldflags "$(LDFLAGSSTRING)"
cannon:
env GO111MODULE=on GOOS=$(TARGETOS) GOARCH=$(TARGETARCH) go build -v $(LDFLAGS) -o ./bin/cannon .
clean:
rm -rf bin
elf:
make -C ./example elf
test: elf
go test -v ./...
lint:
golangci-lint run -E goimports,sqlclosecheck,bodyclose,asciicheck,misspell,errorlint --timeout 5m -e "errors.As" -e "errors.Is"
.PHONY: \
cannon \
clean \
test \
lint
...@@ -26,11 +26,11 @@ make op-program # build ...@@ -26,11 +26,11 @@ make op-program # build
# Switch back to cannon, and build the CLI # Switch back to cannon, and build the CLI
cd ../cannon cd ../cannon
go build -o cannon . make cannon
# Transform MIPS op-program client binary into first VM state. # Transform MIPS op-program client binary into first VM state.
# This outputs state.json (VM state) and meta.json (for debug symbols). # This outputs state.json (VM state) and meta.json (for debug symbols).
./cannon load-elf --path=../op-program/bin/op-program-client.elf ./bin/cannon load-elf --path=../op-program/bin/op-program-client.elf
# Run cannon emulator (with example inputs) # Run cannon emulator (with example inputs)
# Note that the server-mode op-program command is passed into cannon (after the --), # Note that the server-mode op-program command is passed into cannon (after the --),
...@@ -39,7 +39,7 @@ go build -o cannon . ...@@ -39,7 +39,7 @@ go build -o cannon .
# Note: # Note:
# - The L2 RPC is an archive L2 node on OP goerli. # - The L2 RPC is an archive L2 node on OP goerli.
# - The L1 RPC is a non-archive RPC, also change `--l1.rpckind` to reflect the correct L1 RPC type. # - The L1 RPC is a non-archive RPC, also change `--l1.rpckind` to reflect the correct L1 RPC type.
./cannon run ./bin/cannon run
--pprof.cpu --pprof.cpu
--info-at '%10000000' --info-at '%10000000'
--proof-at never --proof-at never
...@@ -62,7 +62,7 @@ go build -o cannon . ...@@ -62,7 +62,7 @@ go build -o cannon .
# Add --proof-at '=12345' (or pick other pattern, see --help) # Add --proof-at '=12345' (or pick other pattern, see --help)
# to pick a step to build a proof for (e.g. exact step, every N steps, etc.) # to pick a step to build a proof for (e.g. exact step, every N steps, etc.)
# Also see `./cannon run --help` for more options # Also see `./bin/cannon run --help` for more options
``` ```
## Contracts ## Contracts
......
...@@ -63,6 +63,8 @@ func TestEVM(t *testing.T) { ...@@ -63,6 +63,8 @@ func TestEVM(t *testing.T) {
if strings.HasPrefix(f.Name(), "oracle") { if strings.HasPrefix(f.Name(), "oracle") {
oracle = staticOracle(t, []byte("hello world")) oracle = staticOracle(t, []byte("hello world"))
} }
// Short-circuit early for exit_group.bin
exitGroup := f.Name() == "exit_group.bin"
env, evmState := NewEVMEnv(contracts, addrs) env, evmState := NewEVMEnv(contracts, addrs)
env.Config.Tracer = tracer env.Config.Tracer = tracer
...@@ -83,6 +85,9 @@ func TestEVM(t *testing.T) { ...@@ -83,6 +85,9 @@ func TestEVM(t *testing.T) {
if us.state.PC == endAddr { if us.state.PC == endAddr {
break break
} }
if exitGroup && us.state.Exited {
break
}
insn := state.Memory.GetMemory(state.PC) insn := state.Memory.GetMemory(state.PC)
t.Logf("step: %4d pc: 0x%08x insn: 0x%08x", state.Step, state.PC, insn) t.Logf("step: %4d pc: 0x%08x insn: 0x%08x", state.Step, state.PC, insn)
...@@ -122,11 +127,17 @@ func TestEVM(t *testing.T) { ...@@ -122,11 +127,17 @@ func TestEVM(t *testing.T) {
require.Equal(t, hexutil.Bytes(uniPost).String(), hexutil.Bytes(evmPost).String(), require.Equal(t, hexutil.Bytes(uniPost).String(), hexutil.Bytes(evmPost).String(),
"mipsevm produced different state than EVM") "mipsevm produced different state than EVM")
} }
require.Equal(t, uint32(endAddr), state.PC, "must reach end") if exitGroup {
// inspect test result require.NotEqual(t, uint32(endAddr), us.state.PC, "must not reach end")
done, result := state.Memory.GetMemory(baseAddrEnd+4), state.Memory.GetMemory(baseAddrEnd+8) require.True(t, us.state.Exited, "must set exited state")
require.Equal(t, done, uint32(1), "must be done") require.Equal(t, uint8(1), us.state.ExitCode, "must exit with 1")
require.Equal(t, result, uint32(1), "must have success result") } else {
require.Equal(t, uint32(endAddr), state.PC, "must reach end")
// inspect test result
done, result := state.Memory.GetMemory(baseAddrEnd+4), state.Memory.GetMemory(baseAddrEnd+8)
require.Equal(t, done, uint32(1), "must be done")
require.Equal(t, result, uint32(1), "must have success result")
}
}) })
} }
} }
......
...@@ -8,10 +8,9 @@ md = Cs(CS_ARCH_MIPS, CS_MODE_32 + CS_MODE_BIG_ENDIAN) ...@@ -8,10 +8,9 @@ md = Cs(CS_ARCH_MIPS, CS_MODE_32 + CS_MODE_BIG_ENDIAN)
def maketest(d, out): def maketest(d, out):
with tempfile.NamedTemporaryFile() as nf: with tempfile.NamedTemporaryFile() as nf:
path = "/Users/kafka/fun/mips/mips-gcc-4.8.1/bin/"
print("building", d, "->", out) print("building", d, "->", out)
# which mips is go # which mips is go
ret = os.system("%s/mips-elf-as -defsym big_endian=1 -march=mips32r2 -o %s %s" % (path, nf.name, d)) ret = os.system("mips-linux-gnu-as -defsym big_endian=1 -march=mips32r2 -o %s %s" % (nf.name, d))
assert(ret == 0) assert(ret == 0)
nf.seek(0) nf.seek(0)
elffile = ELFFile(nf) elffile = ELFFile(nf)
...@@ -35,4 +34,4 @@ if __name__ == "__main__": ...@@ -35,4 +34,4 @@ if __name__ == "__main__":
for d in os.listdir("test/"): for d in os.listdir("test/"):
if not d.endswith(".asm"): if not d.endswith(".asm"):
continue continue
maketest("test/"+d, "test/bin/"+(d.replace(".asm", ".bin"))) maketest("test/"+d, "test/bin/"+(d.replace(".asm", ".bin")))
\ No newline at end of file
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
li $v0, 4045
syscall
lui $t0, 0x4000
subu $v0, $v0, $t0
sltiu $v0, $v0, 1
# save results
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
li $v0, 4120
syscall
li $t0, 0x1
subu $v0, $v0, $t0
sltiu $v0, $v0, 1
# save results
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
li $a0, 1
li $v0, 4246
syscall
# Unreachable ....
# set test result to fail.
# Test runner should short-circuit before reaching this point.
li $v0, 0
# save results
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
# fnctl(0, 3)
li $v0, 4055
li $a0, 0x0
li $a1, 0x3
syscall
sltiu $v0, $v0, 1
# save results
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
test:
li $v0, 4090
lui $a0, 0x3000
li $a1, 4096
syscall
lui $t0, 0x3000
subu $v0, $v0, $t0
sltiu $v0, $v0, 1
# save results
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
...@@ -69,6 +69,10 @@ $readloop: ...@@ -69,6 +69,10 @@ $readloop:
addiu $t0, $t0, -1 addiu $t0, $t0, -1
bnez $t0, $readloop bnez $t0, $readloop
nop nop
# reading the pre-image stream at EOF should have no effect
li $a1, 0x31000008
li $v0, 4003
syscall
# length at 0x31000000. We also check that the lower 32 bits are zero # length at 0x31000000. We also check that the lower 32 bits are zero
lui $s1, 0x3100 lui $s1, 0x3100
......
.section .test, "x"
.balign 4
.set noreorder
.global test
.ent test
# load hash at 0x30001000
# 0x47173285 a8d7341e 5e972fc6 77286384 f802f8ef 42a5ec5f 03bbfa25 4cb01fad = keccak("hello world")
# 0x02173285 a8d7341e 5e972fc6 77286384 f802f8ef 42a5ec5f 03bbfa25 4cb01fad = keccak("hello world").key
test:
lui $s0, 0x3000
ori $s0, 0x1000
lui $t0, 0x0217
ori $t0, 0x3285
sw $t0, 0($s0)
lui $t0, 0xa8d7
ori $t0, 0x341e
sw $t0, 4($s0)
lui $t0, 0x5e97
ori $t0, 0x2fc6
sw $t0, 8($s0)
lui $t0, 0x7728
ori $t0, 0x6384
sw $t0, 0xc($s0)
lui $t0, 0xf802
ori $t0, 0xf8ef
sw $t0, 0x10($s0)
lui $t0, 0x42a5
ori $t0, 0xec5f
sw $t0, 0x14($s0)
lui $t0, 0x03bb
ori $t0, 0xfa25
sw $t0, 0x18($s0)
lui $t0, 0x4cb0
ori $t0, 0x1fad
sw $t0, 0x1c($s0)
# preimage request - write(fdPreimageWrite, preimageData, 32)
li $a0, 6
li $a1, 0x30001000
li $t0, 8
li $a2, 4
$writeloop:
li $v0, 4004
syscall
addiu $a1, $a1, 4
addiu $t0, $t0, -1
bnez $t0, $writeloop
nop
# preimage response to 0x30002000 - read(fdPreimageRead, addr, count)
# read preimage length to unaligned addr. This will read only up to the nearest aligned byte so we have to read again.
li $a0, 5
li $a1, 0x31000001
li $a2, 4
li $v0, 4003
syscall
li $a1, 0x31000004
li $v0, 4003
syscall
li $a1, 0x31000008
li $a2, 1
li $v0, 4003
syscall
# read the preimage data
li $a1, 0x31000009
li $t0, 11
$readloop:
li $v0, 4003
li $a2, 4
syscall
addu $a1, $a1, $v0
subu $t0, $t0, $v0
bnez $t0, $readloop
nop
# length at 0x31000001. We also check that the lower 32 bits are zero
li $s1, 0x31000001
lb $t0, 0($s1)
lb $t2, 1($s1)
sll $t2, $t2, 8
or $t0, $t0, $t2
lb $t2, 2($s1)
sll $t2, $t2, 16
or $t0, $t0, $t2
# assert len[0:3] == 0
sltiu $v0, $t0, 1
# assert len[4:8] == 0
addiu $s1, $s1, 3
lw $t1, 0($s1)
sltiu $v1, $t1, 1
and $v0, $v0, $v1
# assert len[8:9] == 11
addiu $s1, $s1, 4
lb $t2, 0($s1)
li $t4, 11
subu $t5, $t2, $t4
sltiu $v1, $t5, 1
and $v0, $v0, $v1
# data at 0x31000009
addiu $s1, $s1, 1
lb $t0, 0($s1)
lb $t2, 1($s1)
sll $t0, $t0, 8
or $t0, $t0, $t2
lb $t2, 2($s1)
sll $t0, $t0, 8
or $t0, $t0, $t2
lb $t2, 3($s1)
sll $t0, $t0, 8
or $t0, $t0, $t2
#lw $t0, 0($s1)
lui $t4, 0x6865
ori $t4, 0x6c6c
subu $t5, $t0, $t4
sltiu $v1, $t5, 1
and $v0, $v0, $v1
# save results
lui $s0, 0xbfff # Load the base address 0xbffffff0
ori $s0, 0xfff0
ori $s1, $0, 1 # Prepare the 'done' status
sw $v0, 8($s0) # Set the test result
sw $s1, 4($s0) # Set 'done'
$done:
jr $ra
nop
.end test
...@@ -35,6 +35,9 @@ func TestState(t *testing.T) { ...@@ -35,6 +35,9 @@ func TestState(t *testing.T) {
if strings.HasPrefix(f.Name(), "oracle") { if strings.HasPrefix(f.Name(), "oracle") {
oracle = staticOracle(t, []byte("hello world")) oracle = staticOracle(t, []byte("hello world"))
} }
// Short-circuit early for exit_group.bin
exitGroup := f.Name() == "exit_group.bin"
// TODO: currently tests are compiled as flat binary objects // TODO: currently tests are compiled as flat binary objects
// We can use more standard tooling to compile them to ELF files and get remove maketests.py // We can use more standard tooling to compile them to ELF files and get remove maketests.py
fn := path.Join("open_mips_tests/test/bin", f.Name()) fn := path.Join("open_mips_tests/test/bin", f.Name())
...@@ -57,14 +60,24 @@ func TestState(t *testing.T) { ...@@ -57,14 +60,24 @@ func TestState(t *testing.T) {
if us.state.PC == endAddr { if us.state.PC == endAddr {
break break
} }
if exitGroup && us.state.Exited {
break
}
_, err := us.Step(false) _, err := us.Step(false)
require.NoError(t, err) require.NoError(t, err)
} }
require.Equal(t, uint32(endAddr), us.state.PC, "must reach end")
// inspect test result if exitGroup {
done, result := state.Memory.GetMemory(baseAddrEnd+4), state.Memory.GetMemory(baseAddrEnd+8) require.NotEqual(t, uint32(endAddr), us.state.PC, "must not reach end")
require.Equal(t, done, uint32(1), "must be done") require.True(t, us.state.Exited, "must set exited state")
require.Equal(t, result, uint32(1), "must have success result") require.Equal(t, uint8(1), us.state.ExitCode, "must exit with 1")
} else {
require.Equal(t, uint32(endAddr), us.state.PC, "must reach end")
done, result := state.Memory.GetMemory(baseAddrEnd+4), state.Memory.GetMemory(baseAddrEnd+8)
// inspect test result
require.Equal(t, done, uint32(1), "must be done")
require.Equal(t, result, uint32(1), "must have success result")
}
}) })
} }
} }
......
...@@ -33,7 +33,6 @@ flag_management: ...@@ -33,7 +33,6 @@ flag_management:
- name: common-ts-tests - name: common-ts-tests
- name: contracts-tests - name: contracts-tests
- name: core-utils-tests - name: core-utils-tests
- name: contracts-periphery-tests
- name: dtl-tests - name: dtl-tests
- name: chain-mon-tests - name: chain-mon-tests
- name: fault-detector-tests - name: fault-detector-tests
......
...@@ -30,7 +30,7 @@ You’ll need the following software installed to follow this tutorial: ...@@ -30,7 +30,7 @@ You’ll need the following software installed to follow this tutorial:
- [Git](https://git-scm.com/) - [Git](https://git-scm.com/)
- [Go](https://go.dev/) - [Go](https://go.dev/)
- [Node](https://nodejs.org/en/) - [Node](https://nodejs.org/en/)
- [Yarn](https://classic.yarnpkg.com/lang/en/docs/install/) - [Pnpm](https://classic.yarnpkg.com/lang/en/docs/install/)
- [Foundry](https://github.com/foundry-rs/foundry#installation) - [Foundry](https://github.com/foundry-rs/foundry#installation)
- [Make](https://linux.die.net/man/1/make) - [Make](https://linux.die.net/man/1/make)
- [jq](https://github.com/jqlang/jq) - [jq](https://github.com/jqlang/jq)
...@@ -44,7 +44,7 @@ This tutorial was checked on: ...@@ -44,7 +44,7 @@ This tutorial was checked on:
| git, curl, jq, and make | OS default | `sudo apt install -y git curl make jq` | | git, curl, jq, and make | OS default | `sudo apt install -y git curl make jq` |
| Go | 1.20 | `sudo apt update` <br> `wget https://go.dev/dl/go1.20.linux-amd64.tar.gz` <br> `tar xvzf go1.20.linux-amd64.tar.gz` <br> `sudo cp go/bin/go /usr/bin/go` <br> `sudo mv go /usr/lib` <br> `echo export GOROOT=/usr/lib/go >> ~/.bashrc` | Go | 1.20 | `sudo apt update` <br> `wget https://go.dev/dl/go1.20.linux-amd64.tar.gz` <br> `tar xvzf go1.20.linux-amd64.tar.gz` <br> `sudo cp go/bin/go /usr/bin/go` <br> `sudo mv go /usr/lib` <br> `echo export GOROOT=/usr/lib/go >> ~/.bashrc`
| Node | 16.19.0 | `curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -` <br> `sudo apt-get install -y nodejs npm` | Node | 16.19.0 | `curl -fsSL https://deb.nodesource.com/setup_16.x | sudo -E bash -` <br> `sudo apt-get install -y nodejs npm`
| yarn | 1.22.19 | `sudo npm install -g yarn` | pnpm | 8.5.6 | `sudo npm install -g pnpm`
| Foundry | 0.2.0 | `yarn install:foundry` | Foundry | 0.2.0 | `yarn install:foundry`
## Build the Source Code ## Build the Source Code
...@@ -69,14 +69,14 @@ We’re going to be spinning up an EVM Rollup from the OP Stack source code. Yo ...@@ -69,14 +69,14 @@ We’re going to be spinning up an EVM Rollup from the OP Stack source code. Yo
1. Install required modules. This is a slow process, while it is running you can already start building `op-geth`, as shown below. 1. Install required modules. This is a slow process, while it is running you can already start building `op-geth`, as shown below.
```bash ```bash
yarn install pnpm install
``` ```
1. Build the various packages inside of the Optimism Monorepo. 1. Build the various packages inside of the Optimism Monorepo.
```bash ```bash
make op-node op-batcher op-proposer make op-node op-batcher op-proposer
yarn build pnpm build
``` ```
### Build op-geth ### Build op-geth
...@@ -278,7 +278,7 @@ We’ve set up the L1 side of things, but now we need to set up the L2 side of t ...@@ -278,7 +278,7 @@ We’ve set up the L1 side of things, but now we need to set up the L2 side of t
You should then see the `genesis.json` and `rollup.json` files inside the `op-node` package. You should then see the `genesis.json` and `rollup.json` files inside the `op-node` package.
1. Next, generate the `jwt.txt` file with the following command: 1. Next, generate the `jwt.txt` file with the following command:
```bash ```bash
openssl rand -hex 32 > jwt.txt openssl rand -hex 32 > jwt.txt
...@@ -307,24 +307,6 @@ We’re almost ready to run our chain! Now we just need to run a few commands to ...@@ -307,24 +307,6 @@ We’re almost ready to run our chain! Now we just need to run a few commands to
mkdir datadir mkdir datadir
``` ```
1. Put a password file into the data directory folder:
```bash
echo "pwd" > datadir/password
```
1. Put the `Sequencer` private key into the data directory folder (don’t include a “0x” prefix):
```bash
echo "<SEQUENCER KEY HERE>" > datadir/block-signer-key
```
1. Import the key into `op-geth`:
```bash
./build/bin/geth account import --datadir=datadir --password=datadir/password datadir/block-signer-key
```
1. Next we need to initialize `op-geth` with the genesis file we generated and copied earlier: 1. Next we need to initialize `op-geth` with the genesis file we generated and copied earlier:
```bash ```bash
...@@ -344,7 +326,6 @@ Set these environment variables for the configuration ...@@ -344,7 +326,6 @@ Set these environment variables for the configuration
| Variable | Value | | Variable | Value |
| -------------- | - | -------------- | -
| `SEQ_ADDR` | Address of the `Sequencer` account
| `SEQ_KEY` | Private key of the `Sequencer` account | `SEQ_KEY` | Private key of the `Sequencer` account
| `BATCHER_KEY` | Private key of the `Batcher` accounts, which should have at least 1 ETH | `BATCHER_KEY` | Private key of the `Batcher` accounts, which should have at least 1 ETH
| `PROPOSER_KEY` | Private key of the `Proposer` account | `PROPOSER_KEY` | Private key of the `Proposer` account
...@@ -360,32 +341,27 @@ Run `op-geth` with the following commands. ...@@ -360,32 +341,27 @@ Run `op-geth` with the following commands.
cd ~/op-geth cd ~/op-geth
./build/bin/geth \ ./build/bin/geth \
--datadir ./datadir \ --datadir ./datadir \
--http \ --http \
--http.corsdomain="*" \ --http.corsdomain="*" \
--http.vhosts="*" \ --http.vhosts="*" \
--http.addr=0.0.0.0 \ --http.addr=0.0.0.0 \
--http.api=web3,debug,eth,txpool,net,engine \ --http.api=web3,debug,eth,txpool,net,engine \
--ws \ --ws \
--ws.addr=0.0.0.0 \ --ws.addr=0.0.0.0 \
--ws.port=8546 \ --ws.port=8546 \
--ws.origins="*" \ --ws.origins="*" \
--ws.api=debug,eth,txpool,net,engine \ --ws.api=debug,eth,txpool,net,engine \
--syncmode=full \ --syncmode=full \
--gcmode=archive \ --gcmode=archive \
--nodiscover \ --nodiscover \
--maxpeers=0 \ --maxpeers=0 \
--networkid=42069 \ --networkid=42069 \
--authrpc.vhosts="*" \ --authrpc.vhosts="*" \
--authrpc.addr=0.0.0.0 \ --authrpc.addr=0.0.0.0 \
--authrpc.port=8551 \ --authrpc.port=8551 \
--authrpc.jwtsecret=./jwt.txt \ --authrpc.jwtsecret=./jwt.txt \
--rollup.disabletxpoolgossip=true \ --rollup.disabletxpoolgossip=true
--password=./datadir/password \
--allow-insecure-unlock \
--mine \
--miner.etherbase=$SEQ_ADDR \
--unlock=$SEQ_ADDR
``` ```
And `op-geth` should be running! You should see some output, but you won’t see any blocks being created yet because `op-geth` is driven by the `op-node`. We’ll need to get that running next. And `op-geth` should be running! You should see some output, but you won’t see any blocks being created yet because `op-geth` is driven by the `op-node`. We’ll need to get that running next.
...@@ -443,7 +419,7 @@ cd ~/optimism/op-node ...@@ -443,7 +419,7 @@ cd ~/optimism/op-node
./bin/op-node \ ./bin/op-node \
--l2=http://localhost:8551 \ --l2=http://localhost:8551 \
--l2.jwt-secret=./jwt.txt \ --l2.jwt-secret=./jwt.txt \
--sequencer.enabled \ --sequencer.enabled \
--sequencer.l1-confs=3 \ --sequencer.l1-confs=3 \
--verifier.l1-confs=3 \ --verifier.l1-confs=3 \
......
...@@ -7,7 +7,9 @@ ...@@ -7,7 +7,9 @@
"nx.json": "*", "nx.json": "*",
"tsconfig.json": "*", "tsconfig.json": "*",
".foundryrc": "*", ".foundryrc": "*",
".nvmrc": "*" "pnpm.lock.yaml": "*",
".npmrc": "*",
".nvmrc": "*"
}, },
"tasksRunnerOptions": { "tasksRunnerOptions": {
"default": { "default": {
......
SHELL := /bin/bash SHELL := /bin/bash
pkg := bindings pkg := bindings
contracts-dir := ../packages/contracts-bedrock monorepo-base := $(shell dirname $(realpath .))
contracts-dir := $(monorepo-base)/packages/contracts-bedrock
all: version mkdir bindings all: version mkdir bindings
...@@ -17,11 +18,12 @@ bindings: compile bindings-build ...@@ -17,11 +18,12 @@ bindings: compile bindings-build
bindings-build: bindings-build:
go run ./gen/main.go \ go run ./gen/main.go \
-forge-artifacts ../packages/contracts-bedrock/forge-artifacts \ -forge-artifacts $(contracts-dir)/forge-artifacts \
-out ./bindings \ -out ./bindings \
-contracts ./artifacts.json \ -contracts ./artifacts.json \
-source-maps MIPS,PreimageOracle \ -source-maps MIPS,PreimageOracle \
-package $(pkg) -package $(pkg) \
-monorepo-base $(monorepo-base)
mkdir: mkdir:
mkdir -p $(pkg) mkdir -p $(pkg)
......
package ast package ast
import ( import (
"path/filepath"
"regexp" "regexp"
"sort" "sort"
"strconv" "strconv"
...@@ -33,7 +34,7 @@ type typeRemapping struct { ...@@ -33,7 +34,7 @@ type typeRemapping struct {
// inefficiency comes from replaceType, which performs a linear // inefficiency comes from replaceType, which performs a linear
// search of all replacements when performing substring matches of // search of all replacements when performing substring matches of
// composite types. // composite types.
func CanonicalizeASTIDs(in *solc.StorageLayout) *solc.StorageLayout { func CanonicalizeASTIDs(in *solc.StorageLayout, monorepoBase string) *solc.StorageLayout {
lastId := uint(1000) lastId := uint(1000)
astIDRemappings := make(map[uint]uint) astIDRemappings := make(map[uint]uint)
typeRemappings := make(map[string]string) typeRemappings := make(map[string]string)
...@@ -83,9 +84,18 @@ func CanonicalizeASTIDs(in *solc.StorageLayout) *solc.StorageLayout { ...@@ -83,9 +84,18 @@ func CanonicalizeASTIDs(in *solc.StorageLayout) *solc.StorageLayout {
Types: make(map[string]solc.StorageLayoutType), Types: make(map[string]solc.StorageLayoutType),
} }
for _, slot := range in.Storage { for _, slot := range in.Storage {
contract := slot.Contract
// Normalize the name of the contract since absolute paths
// are used when there are 2 contracts imported with the same
// name
if filepath.IsAbs(contract) {
contract = strings.TrimPrefix(strings.Replace(contract, monorepoBase, "", 1), "/")
}
outLayout.Storage = append(outLayout.Storage, solc.StorageLayoutEntry{ outLayout.Storage = append(outLayout.Storage, solc.StorageLayoutEntry{
AstId: astIDRemappings[slot.AstId], AstId: astIDRemappings[slot.AstId],
Contract: slot.Contract, Contract: contract,
Label: slot.Label, Label: slot.Label,
Offset: slot.Offset, Offset: slot.Offset,
Slot: slot.Slot, Slot: slot.Slot,
......
...@@ -49,7 +49,7 @@ func TestCanonicalize(t *testing.T) { ...@@ -49,7 +49,7 @@ func TestCanonicalize(t *testing.T) {
// Run 100 times to make sure that we aren't relying // Run 100 times to make sure that we aren't relying
// on random map iteration order. // on random map iteration order.
for i := 0; i < 100; i++ { for i := 0; i < 100; i++ {
require.Equal(t, testData.Out, CanonicalizeASTIDs(testData.In)) require.Equal(t, testData.Out, CanonicalizeASTIDs(testData.In, ""))
} }
}) })
} }
......
...@@ -9,7 +9,7 @@ import ( ...@@ -9,7 +9,7 @@ import (
"github.com/ethereum-optimism/optimism/op-bindings/solc" "github.com/ethereum-optimism/optimism/op-bindings/solc"
) )
const ERC20StorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_balances\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1001,\"contract\":\"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_allowances\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_address,t_mapping(t_address,t_uint256))\"},{\"astId\":1002,\"contract\":\"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_totalSupply\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_uint256\"},{\"astId\":1003,\"contract\":\"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_name\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_string_storage\"},{\"astId\":1004,\"contract\":\"node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_symbol\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_string_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_mapping(t_address,t_mapping(t_address,t_uint256))\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e mapping(address =\u003e uint256))\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_mapping(t_address,t_uint256)\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_string_storage\":{\"encoding\":\"bytes\",\"label\":\"string\",\"numberOfBytes\":\"32\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}" const ERC20StorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"node_modules/.pnpm/@openzeppelin+contracts@4.7.3/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_balances\",\"offset\":0,\"slot\":\"0\",\"type\":\"t_mapping(t_address,t_uint256)\"},{\"astId\":1001,\"contract\":\"node_modules/.pnpm/@openzeppelin+contracts@4.7.3/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_allowances\",\"offset\":0,\"slot\":\"1\",\"type\":\"t_mapping(t_address,t_mapping(t_address,t_uint256))\"},{\"astId\":1002,\"contract\":\"node_modules/.pnpm/@openzeppelin+contracts@4.7.3/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_totalSupply\",\"offset\":0,\"slot\":\"2\",\"type\":\"t_uint256\"},{\"astId\":1003,\"contract\":\"node_modules/.pnpm/@openzeppelin+contracts@4.7.3/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_name\",\"offset\":0,\"slot\":\"3\",\"type\":\"t_string_storage\"},{\"astId\":1004,\"contract\":\"node_modules/.pnpm/@openzeppelin+contracts@4.7.3/node_modules/@openzeppelin/contracts/token/ERC20/ERC20.sol:ERC20\",\"label\":\"_symbol\",\"offset\":0,\"slot\":\"4\",\"type\":\"t_string_storage\"}],\"types\":{\"t_address\":{\"encoding\":\"inplace\",\"label\":\"address\",\"numberOfBytes\":\"20\"},\"t_mapping(t_address,t_mapping(t_address,t_uint256))\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e mapping(address =\u003e uint256))\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_mapping(t_address,t_uint256)\"},\"t_mapping(t_address,t_uint256)\":{\"encoding\":\"mapping\",\"label\":\"mapping(address =\u003e uint256)\",\"numberOfBytes\":\"32\",\"key\":\"t_address\",\"value\":\"t_uint256\"},\"t_string_storage\":{\"encoding\":\"bytes\",\"label\":\"string\",\"numberOfBytes\":\"32\"},\"t_uint256\":{\"encoding\":\"inplace\",\"label\":\"uint256\",\"numberOfBytes\":\"32\"}}}"
var ERC20StorageLayout = new(solc.StorageLayout) var ERC20StorageLayout = new(solc.StorageLayout)
......
...@@ -31,7 +31,7 @@ var ( ...@@ -31,7 +31,7 @@ var (
// FaultDisputeGameMetaData contains all meta data concerning the FaultDisputeGame contract. // FaultDisputeGameMetaData contains all meta data concerning the FaultDisputeGame contract.
var FaultDisputeGameMetaData = &bind.MetaData{ var FaultDisputeGameMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"Claim\",\"name\":\"_absolutePrestate\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_maxGameDepth\",\"type\":\"uint256\"},{\"internalType\":\"contractIBigStepper\",\"name\":\"_vm\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotDefendRootClaim\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ClaimAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ClockNotExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ClockTimeExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GameDepthExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GameNotInProgress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidParent\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPrestate\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValidStep\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"parentIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"Claim\",\"name\":\"claim\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"claimant\",\"type\":\"address\"}],\"name\":\"Move\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"enumGameStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"name\":\"Resolved\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ABSOLUTE_PRESTATE\",\"outputs\":[{\"internalType\":\"Claim\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_GAME_DEPTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VM\",\"outputs\":[{\"internalType\":\"contractIBigStepper\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_parentIndex\",\"type\":\"uint256\"},{\"internalType\":\"Claim\",\"name\":\"_claim\",\"type\":\"bytes32\"}],\"name\":\"attack\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"bondManager\",\"outputs\":[{\"internalType\":\"contractIBondManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"claimData\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"parentIndex\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"countered\",\"type\":\"bool\"},{\"internalType\":\"Claim\",\"name\":\"claim\",\"type\":\"bytes32\"},{\"internalType\":\"Position\",\"name\":\"position\",\"type\":\"uint128\"},{\"internalType\":\"Clock\",\"name\":\"clock\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimDataLen\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"len_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createdAt\",\"outputs\":[{\"internalType\":\"Timestamp\",\"name\":\"createdAt_\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_parentIndex\",\"type\":\"uint256\"},{\"internalType\":\"Claim\",\"name\":\"_claim\",\"type\":\"bytes32\"}],\"name\":\"defend\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"extraData\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"extraData_\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gameData\",\"outputs\":[{\"internalType\":\"GameType\",\"name\":\"gameType_\",\"type\":\"uint8\"},{\"internalType\":\"Claim\",\"name\":\"rootClaim_\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"extraData_\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gameStart\",\"outputs\":[{\"internalType\":\"Timestamp\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gameType\",\"outputs\":[{\"internalType\":\"GameType\",\"name\":\"gameType_\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2BlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"l2BlockNumber_\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_challengeIndex\",\"type\":\"uint256\"},{\"internalType\":\"Claim\",\"name\":\"_claim\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"_isAttack\",\"type\":\"bool\"}],\"name\":\"move\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resolve\",\"outputs\":[{\"internalType\":\"enumGameStatus\",\"name\":\"status_\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootClaim\",\"outputs\":[{\"internalType\":\"Claim\",\"name\":\"rootClaim_\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"status\",\"outputs\":[{\"internalType\":\"enumGameStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_claimIndex\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_isAttack\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"_stateData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_proof\",\"type\":\"bytes\"}],\"name\":\"step\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", ABI: "[{\"inputs\":[{\"internalType\":\"Claim\",\"name\":\"_absolutePrestate\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_maxGameDepth\",\"type\":\"uint256\"},{\"internalType\":\"contractIBigStepper\",\"name\":\"_vm\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"inputs\":[],\"name\":\"CannotDefendRootClaim\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ClaimAlreadyExists\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ClockNotExpired\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ClockTimeExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GameDepthExceeded\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"GameNotInProgress\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidParent\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"InvalidPrestate\",\"type\":\"error\"},{\"inputs\":[],\"name\":\"ValidStep\",\"type\":\"error\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"uint256\",\"name\":\"parentIndex\",\"type\":\"uint256\"},{\"indexed\":true,\"internalType\":\"Claim\",\"name\":\"claim\",\"type\":\"bytes32\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"claimant\",\"type\":\"address\"}],\"name\":\"Move\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"enumGameStatus\",\"name\":\"status\",\"type\":\"uint8\"}],\"name\":\"Resolved\",\"type\":\"event\"},{\"inputs\":[],\"name\":\"ABSOLUTE_PRESTATE\",\"outputs\":[{\"internalType\":\"Claim\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"MAX_GAME_DEPTH\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"VM\",\"outputs\":[{\"internalType\":\"contractIBigStepper\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_parentIndex\",\"type\":\"uint256\"},{\"internalType\":\"Claim\",\"name\":\"_claim\",\"type\":\"bytes32\"}],\"name\":\"attack\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"bondManager\",\"outputs\":[{\"internalType\":\"contractIBondManager\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"claimData\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"parentIndex\",\"type\":\"uint32\"},{\"internalType\":\"bool\",\"name\":\"countered\",\"type\":\"bool\"},{\"internalType\":\"Claim\",\"name\":\"claim\",\"type\":\"bytes32\"},{\"internalType\":\"Position\",\"name\":\"position\",\"type\":\"uint128\"},{\"internalType\":\"Clock\",\"name\":\"clock\",\"type\":\"uint128\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"claimDataLen\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"len_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"createdAt\",\"outputs\":[{\"internalType\":\"Timestamp\",\"name\":\"createdAt_\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_parentIndex\",\"type\":\"uint256\"},{\"internalType\":\"Claim\",\"name\":\"_claim\",\"type\":\"bytes32\"}],\"name\":\"defend\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"extraData\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"extraData_\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gameData\",\"outputs\":[{\"internalType\":\"GameType\",\"name\":\"gameType_\",\"type\":\"uint8\"},{\"internalType\":\"Claim\",\"name\":\"rootClaim_\",\"type\":\"bytes32\"},{\"internalType\":\"bytes\",\"name\":\"extraData_\",\"type\":\"bytes\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gameStart\",\"outputs\":[{\"internalType\":\"Timestamp\",\"name\":\"\",\"type\":\"uint64\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"gameType\",\"outputs\":[{\"internalType\":\"GameType\",\"name\":\"gameType_\",\"type\":\"uint8\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"initialize\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"l2BlockNumber\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"l2BlockNumber_\",\"type\":\"uint256\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_challengeIndex\",\"type\":\"uint256\"},{\"internalType\":\"Claim\",\"name\":\"_claim\",\"type\":\"bytes32\"},{\"internalType\":\"bool\",\"name\":\"_isAttack\",\"type\":\"bool\"}],\"name\":\"move\",\"outputs\":[],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"resolve\",\"outputs\":[{\"internalType\":\"enumGameStatus\",\"name\":\"status_\",\"type\":\"uint8\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"rootClaim\",\"outputs\":[{\"internalType\":\"Claim\",\"name\":\"rootClaim_\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"status\",\"outputs\":[{\"internalType\":\"enumGameStatus\",\"name\":\"\",\"type\":\"uint8\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_claimIndex\",\"type\":\"uint256\"},{\"internalType\":\"bool\",\"name\":\"_isAttack\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"_stateData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"_proof\",\"type\":\"bytes\"}],\"name\":\"step\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"version\",\"outputs\":[{\"internalType\":\"string\",\"name\":\"\",\"type\":\"string\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
Bin: "0x61014060405234801561001157600080fd5b506040516120503803806120508339810160408190526100309161005b565b6000608081905260a052600260c05260e092909252610100526001600160a01b0316610120526100a1565b60008060006060848603121561007057600080fd5b83516020850151604086015191945092506001600160a01b038116811461009657600080fd5b809150509250925092565b60805160a05160c05160e0516101005161012051611f3d610113600039600081816103aa015261140c0152600081816102c20152818161061701528181610b7501526111da0152600081816101bd01526113140152600061095d015260006109340152600061090b0152611f3d6000f3fe60806040526004361061016a5760003560e01c80638129fc1c116100cb578063bcef3b551161007f578063cf09e0d011610059578063cf09e0d01461049c578063d8cc1a3c146104bb578063fa24f743146104db57600080fd5b8063bcef3b55146103e8578063c55cd0c714610425578063c6f0308c1461043857600080fd5b80638b85902b116100b05780638b85902b146103585780639293129814610398578063bbdc02db146103cc57600080fd5b80638129fc1c1461032e5780638980e0cc1461034357600080fd5b8063363cc4271161012257806354fd4d501161010757806354fd4d50146102e4578063609d333414610306578063632247ea1461031b57600080fd5b8063363cc427146102515780634778efe8146102b057600080fd5b80632810e1d6116101535780632810e1d6146101ed5780633218b99d1461020257806335fef5671461023c57600080fd5b8063200d2ed21461016f578063266198f9146101ab575b600080fd5b34801561017b57600080fd5b506000546101959068010000000000000000900460ff1681565b6040516101a291906119e7565b60405180910390f35b3480156101b757600080fd5b506101df7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016101a2565b3480156101f957600080fd5b506101956104ff565b34801561020e57600080fd5b506000546102239067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101a2565b61024f61024a366004611a28565b6108f4565b005b34801561025d57600080fd5b5060005461028b906901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a2565b3480156102bc57600080fd5b506101df7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102f057600080fd5b506102f9610904565b6040516101a29190611ac4565b34801561031257600080fd5b506102f96109a7565b61024f610329366004611af3565b6109b9565b34801561033a57600080fd5b5061024f610f73565b34801561034f57600080fd5b506001546101df565b34801561036457600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003602001356101df565b3480156103a457600080fd5b5061028b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103d857600080fd5b50604051600081526020016101a2565b3480156103f457600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003356101df565b61024f610433366004611a28565b6110b4565b34801561044457600080fd5b50610458610453366004611b28565b6110c0565b6040805163ffffffff90961686529315156020860152928401919091526fffffffffffffffffffffffffffffffff908116606084015216608082015260a0016101a2565b3480156104a857600080fd5b5060005467ffffffffffffffff16610223565b3480156104c757600080fd5b5061024f6104d6366004611b8a565b611131565b3480156104e757600080fd5b506104f06114fb565b6040516101a293929190611c14565b60008060005468010000000000000000900460ff166002811115610525576105256119b8565b1461055c576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805460009161056c91611c6e565b90506fffffffffffffffffffffffffffffffff815b67ffffffffffffffff811015610656576000600182815481106105a6576105a6611c85565b6000918252602090912060039091020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019290915060ff64010000000090910416156105f75750610581565b600281015460009061063b906fffffffffffffffffffffffffffffffff167f0000000000000000000000000000000000000000000000000000000000000000611539565b90508381101561064f578093508260010194505b5050610581565b5060006001838154811061066c5761066c611c85565b600091825260208220600390910201805490925063ffffffff908116919082146106d657600182815481106106a3576106a3611c85565b906000526020600020906003020160020160109054906101000a90046fffffffffffffffffffffffffffffffff16610702565b600283015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff165b905062049d4061071c67ffffffffffffffff831642611c6e565b610738836fffffffffffffffffffffffffffffffff1660401c90565b67ffffffffffffffff1661074c9190611cb4565b11610783576040517ff2440b5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600283810154610825906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b61082f9190611cfb565b67ffffffffffffffff1615801561085657506fffffffffffffffffffffffffffffffff8414155b156108645760029550610869565b600195505b600080548791907fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000008360028111156108ae576108ae6119b8565b0217905560028111156108c3576108c36119b8565b6040517f5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da6090600090a2505050505090565b610900828260006109b9565b5050565b606061092f7f00000000000000000000000000000000000000000000000000000000000000006115ee565b6109587f00000000000000000000000000000000000000000000000000000000000000006115ee565b6109817f00000000000000000000000000000000000000000000000000000000000000006115ee565b60405160200161099393929190611d22565b604051602081830303815290604052905090565b60606109b460208061172b565b905090565b6000805468010000000000000000900460ff1660028111156109dd576109dd6119b8565b14610a14576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82158015610a20575080155b15610a57576040517fa42637bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060018481548110610a6c57610a6c611c85565b60009182526020918290206040805160a0810182526003909302909101805463ffffffff8116845260ff64010000000090910416151593830193909352600180840154918301919091526002909201546fffffffffffffffffffffffffffffffff80821660608401527001000000000000000000000000000000009091041660808201528154909250819086908110610b0757610b07611c85565b6000918252602082206003909102018054921515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff909316929092179091556060820151610b71906fffffffffffffffffffffffffffffffff1684151760011b90565b90507f0000000000000000000000000000000000000000000000000000000000000000610c30826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff161115610c72576040517f56f57b2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815160009063ffffffff90811614610cd2576001836000015163ffffffff1681548110610ca157610ca1611c85565b906000526020600020906003020160020160109054906101000a90046fffffffffffffffffffffffffffffffff1690505b608083015160009067ffffffffffffffff1667ffffffffffffffff1642610d0b846fffffffffffffffffffffffffffffffff1660401c90565b67ffffffffffffffff16610d1f9190611cb4565b610d299190611c6e565b905062049d4067ffffffffffffffff82161115610d72576040517f3381d11400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000604082901b421790506000610d93888660009182526020526040902090565b60008181526002602052604090205490915060ff1615610ddf576040517f80497e3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260026020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155815160a08101835263ffffffff808f1682529381018581528184018e81526fffffffffffffffffffffffffffffffff808d16606085019081528a82166080860190815286548088018855968a52945160039096027fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf68101805495511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000909616979099169690961793909317909655517fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf78401555190518416700100000000000000000000000000000000029316929092177fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf8909201919091555133918a918c917f9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be91a4505050505050505050565b600080547fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000164267ffffffffffffffff161781556040805160a08101825263ffffffff81526020810192909252600191908101610ff87ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe369081013560f01c90033590565b815260016020820152604001426fffffffffffffffffffffffffffffffff908116909152825460018181018555600094855260209485902084516003909302018054958501511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090961663ffffffff909316929092179490941781556040830151938101939093556060820151608090920151811670010000000000000000000000000000000002911617600290910155565b610900828260016109b9565b600181815481106110d057600080fd5b600091825260209091206003909102018054600182015460029092015463ffffffff8216935064010000000090910460ff1691906fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041685565b6000805468010000000000000000900460ff166002811115611155576111556119b8565b1461118c576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600187815481106111a1576111a1611c85565b6000918252602082206003919091020160028101549092506fffffffffffffffffffffffffffffffff16908715821760011b90506112007f00000000000000000000000000000000000000000000000000000000000000006001611cb4565b61129c826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff16146112dd576040517f5f53dd9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080891561136357611301836fffffffffffffffffffffffffffffffff166117c2565b67ffffffffffffffff1660000361133a577f00000000000000000000000000000000000000000000000000000000000000009150611358565b611355611348600186611d98565b865463ffffffff16611868565b91505b50600184015461137d565b8460010154915061137a8460016113489190611dc9565b90505b81898960405161138e929190611dfd565b6040518091039020146113cd576040517f696550ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff8e0cb96000000000000000000000000000000000000000000000000000000008152819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f8e0cb9690611447908d908d908d908d90600401611e56565b6020604051808303816000875af1158015611466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148a9190611e88565b036114c1576040517ffb4e40dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505082547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff16640100000000179092555050505050505050565b6000367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90033560606115326109a7565b9050909192565b6000806115c6847e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1690508083036001841b600180831b0386831b17039250505092915050565b60608160000361163157505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561165b578061164581611ea1565b91506116549050600a83611ed9565b9150611635565b60008167ffffffffffffffff81111561167657611676611eed565b6040519080825280601f01601f1916602001820160405280156116a0576020820181803683370190505b5090505b8415611723576116b5600183611c6e565b91506116c2600a86611f1c565b6116cd906030611cb4565b60f81b8183815181106116e2576116e2611c85565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061171c600a86611ed9565b94506116a4565b949350505050565b6060600061176284367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003611cb4565b90508267ffffffffffffffff1667ffffffffffffffff81111561178757611787611eed565b6040519080825280601f01601f1916602001820160405280156117b1576020820181803683370190505b509150828160208401375092915050565b60008061184f837e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b600167ffffffffffffffff919091161b90920392915050565b600080611886846fffffffffffffffffffffffffffffffff1661190c565b905060006001848154811061189d5761189d611c85565b906000526020600020906003020190505b60028101546fffffffffffffffffffffffffffffffff83811691161461190057805460018054909163ffffffff169081106118eb576118eb611c85565b906000526020600020906003020190506118ae565b60010154949350505050565b600081196001830116816119a0827e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff169390931c8015179392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160038310611a22577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60008060408385031215611a3b57600080fd5b50508035926020909101359150565b60005b83811015611a65578181015183820152602001611a4d565b83811115611a74576000848401525b50505050565b60008151808452611a92816020860160208601611a4a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611ad76020830184611a7a565b9392505050565b80358015158114611aee57600080fd5b919050565b600080600060608486031215611b0857600080fd5b8335925060208401359150611b1f60408501611ade565b90509250925092565b600060208284031215611b3a57600080fd5b5035919050565b60008083601f840112611b5357600080fd5b50813567ffffffffffffffff811115611b6b57600080fd5b602083019150836020828501011115611b8357600080fd5b9250929050565b60008060008060008060808789031215611ba357600080fd5b86359550611bb360208801611ade565b9450604087013567ffffffffffffffff80821115611bd057600080fd5b611bdc8a838b01611b41565b90965094506060890135915080821115611bf557600080fd5b50611c0289828a01611b41565b979a9699509497509295939492505050565b60ff84168152826020820152606060408201526000611c366060830184611a7a565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611c8057611c80611c3f565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008219821115611cc757611cc7611c3f565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600067ffffffffffffffff80841680611d1657611d16611ccc565b92169190910692915050565b60008451611d34818460208901611a4a565b80830190507f2e000000000000000000000000000000000000000000000000000000000000008082528551611d70816001850160208a01611a4a565b60019201918201528351611d8b816002840160208801611a4a565b0160020195945050505050565b60006fffffffffffffffffffffffffffffffff83811690831681811015611dc157611dc1611c3f565b039392505050565b60006fffffffffffffffffffffffffffffffff808316818516808303821115611df457611df4611c3f565b01949350505050565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b604081526000611e6a604083018688611e0d565b8281036020840152611e7d818587611e0d565b979650505050505050565b600060208284031215611e9a57600080fd5b5051919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611ed257611ed2611c3f565b5060010190565b600082611ee857611ee8611ccc565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082611f2b57611f2b611ccc565b50069056fea164736f6c634300080f000a", Bin: "0x61014060405234801561001157600080fd5b50604051620021df380380620021df8339810160408190526100329161005d565b6000608081905260a052600360c05260e092909252610100526001600160a01b0316610120526100a3565b60008060006060848603121561007257600080fd5b83516020850151604086015191945092506001600160a01b038116811461009857600080fd5b809150509250925092565b60805160a05160c05160e05161010051610120516120c962000116600039600081816103aa01526113d60152600081816102c20152818161061701528181610b7501526111da0152600081816101bd01526113140152600061095d015260006109340152600061090b01526120c96000f3fe60806040526004361061016a5760003560e01c80638129fc1c116100cb578063bcef3b551161007f578063cf09e0d011610059578063cf09e0d01461049c578063d8cc1a3c146104bb578063fa24f743146104db57600080fd5b8063bcef3b55146103e8578063c55cd0c714610425578063c6f0308c1461043857600080fd5b80638b85902b116100b05780638b85902b146103585780639293129814610398578063bbdc02db146103cc57600080fd5b80638129fc1c1461032e5780638980e0cc1461034357600080fd5b8063363cc4271161012257806354fd4d501161010757806354fd4d50146102e4578063609d333414610306578063632247ea1461031b57600080fd5b8063363cc427146102515780634778efe8146102b057600080fd5b80632810e1d6116101535780632810e1d6146101ed5780633218b99d1461020257806335fef5671461023c57600080fd5b8063200d2ed21461016f578063266198f9146101ab575b600080fd5b34801561017b57600080fd5b506000546101959068010000000000000000900460ff1681565b6040516101a29190611b52565b60405180910390f35b3480156101b757600080fd5b506101df7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016101a2565b3480156101f957600080fd5b506101956104ff565b34801561020e57600080fd5b506000546102239067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101a2565b61024f61024a366004611b93565b6108f4565b005b34801561025d57600080fd5b5060005461028b906901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a2565b3480156102bc57600080fd5b506101df7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102f057600080fd5b506102f9610904565b6040516101a29190611c2f565b34801561031257600080fd5b506102f96109a7565b61024f610329366004611c5e565b6109b9565b34801561033a57600080fd5b5061024f610f73565b34801561034f57600080fd5b506001546101df565b34801561036457600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003602001356101df565b3480156103a457600080fd5b5061028b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103d857600080fd5b50604051600081526020016101a2565b3480156103f457600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003356101df565b61024f610433366004611b93565b6110b4565b34801561044457600080fd5b50610458610453366004611c93565b6110c0565b6040805163ffffffff90961686529315156020860152928401919091526fffffffffffffffffffffffffffffffff908116606084015216608082015260a0016101a2565b3480156104a857600080fd5b5060005467ffffffffffffffff16610223565b3480156104c757600080fd5b5061024f6104d6366004611cf5565b611131565b3480156104e757600080fd5b506104f061166d565b6040516101a293929190611d7f565b60008060005468010000000000000000900460ff16600281111561052557610525611b23565b1461055c576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805460009161056c91611dd9565b90506fffffffffffffffffffffffffffffffff815b67ffffffffffffffff811015610656576000600182815481106105a6576105a6611df0565b6000918252602090912060039091020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019290915060ff64010000000090910416156105f75750610581565b600281015460009061063b906fffffffffffffffffffffffffffffffff167f00000000000000000000000000000000000000000000000000000000000000006116ab565b90508381101561064f578093508260010194505b5050610581565b5060006001838154811061066c5761066c611df0565b600091825260208220600390910201805490925063ffffffff908116919082146106d657600182815481106106a3576106a3611df0565b906000526020600020906003020160020160109054906101000a90046fffffffffffffffffffffffffffffffff16610702565b600283015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff165b905062049d4061071c67ffffffffffffffff831642611dd9565b610738836fffffffffffffffffffffffffffffffff1660401c90565b67ffffffffffffffff1661074c9190611e1f565b11610783576040517ff2440b5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600283810154610825906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b61082f9190611e66565b67ffffffffffffffff1615801561085657506fffffffffffffffffffffffffffffffff8414155b156108645760029550610869565b600195505b600080548791907fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000008360028111156108ae576108ae611b23565b0217905560028111156108c3576108c3611b23565b6040517f5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da6090600090a2505050505090565b610900828260006109b9565b5050565b606061092f7f0000000000000000000000000000000000000000000000000000000000000000611760565b6109587f0000000000000000000000000000000000000000000000000000000000000000611760565b6109817f0000000000000000000000000000000000000000000000000000000000000000611760565b60405160200161099393929190611e8d565b604051602081830303815290604052905090565b60606109b460208061189d565b905090565b6000805468010000000000000000900460ff1660028111156109dd576109dd611b23565b14610a14576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82158015610a20575080155b15610a57576040517fa42637bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060018481548110610a6c57610a6c611df0565b60009182526020918290206040805160a0810182526003909302909101805463ffffffff8116845260ff64010000000090910416151593830193909352600180840154918301919091526002909201546fffffffffffffffffffffffffffffffff80821660608401527001000000000000000000000000000000009091041660808201528154909250819086908110610b0757610b07611df0565b6000918252602082206003909102018054921515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff909316929092179091556060820151610b71906fffffffffffffffffffffffffffffffff1684151760011b90565b90507f0000000000000000000000000000000000000000000000000000000000000000610c30826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff161115610c72576040517f56f57b2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815160009063ffffffff90811614610cd2576001836000015163ffffffff1681548110610ca157610ca1611df0565b906000526020600020906003020160020160109054906101000a90046fffffffffffffffffffffffffffffffff1690505b608083015160009067ffffffffffffffff1667ffffffffffffffff1642610d0b846fffffffffffffffffffffffffffffffff1660401c90565b67ffffffffffffffff16610d1f9190611e1f565b610d299190611dd9565b905062049d4067ffffffffffffffff82161115610d72576040517f3381d11400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000604082901b421790506000610d93888660009182526020526040902090565b60008181526002602052604090205490915060ff1615610ddf576040517f80497e3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260026020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155815160a08101835263ffffffff808f1682529381018581528184018e81526fffffffffffffffffffffffffffffffff808d16606085019081528a82166080860190815286548088018855968a52945160039096027fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf68101805495511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000909616979099169690961793909317909655517fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf78401555190518416700100000000000000000000000000000000029316929092177fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf8909201919091555133918a918c917f9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be91a4505050505050505050565b600080547fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000164267ffffffffffffffff161781556040805160a08101825263ffffffff81526020810192909252600191908101610ff87ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe369081013560f01c90033590565b815260016020820152604001426fffffffffffffffffffffffffffffffff908116909152825460018181018555600094855260209485902084516003909302018054958501511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090961663ffffffff909316929092179490941781556040830151938101939093556060820151608090920151811670010000000000000000000000000000000002911617600290910155565b610900828260016109b9565b600181815481106110d057600080fd5b600091825260209091206003909102018054600182015460029092015463ffffffff8216935064010000000090910460ff1691906fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041685565b6000805468010000000000000000900460ff16600281111561115557611155611b23565b1461118c576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600187815481106111a1576111a1611df0565b6000918252602082206003919091020160028101549092506fffffffffffffffffffffffffffffffff16908715821760011b90506112007f00000000000000000000000000000000000000000000000000000000000000006001611e1f565b61129c826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff16146112dd576040517f5f53dd9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080891561136357611301836fffffffffffffffffffffffffffffffff16611934565b67ffffffffffffffff1660000361133a577f0000000000000000000000000000000000000000000000000000000000000000915061135c565b611355611348600186611f03565b865463ffffffff166119da565b6001015491505b508361137d565b8460010154915061137a8460016113489190611f34565b90505b81898960405161138e929190611f68565b6040518091039020146113cd576040517f696550ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081600101547f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663f8e0cb968c8c8c8c6040518563ffffffff1660e01b81526004016114339493929190611fc1565b6020604051808303816000875af1158015611452573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114769190611ff3565b600284810154929091149250600091611521906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b6115bd886fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b6115c7919061200c565b6115d19190611e66565b67ffffffffffffffff161590508080156115e85750815b806115fa5750801580156115fa575081155b15611631576040517ffb4e40dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505084547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff166401000000001790945550505050505050505050565b6000367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90033560606116a46109a7565b9050909192565b600080611738847e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1690508083036001841b600180831b0386831b17039250505092915050565b6060816000036117a357505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156117cd57806117b78161202d565b91506117c69050600a83612065565b91506117a7565b60008167ffffffffffffffff8111156117e8576117e8612079565b6040519080825280601f01601f191660200182016040528015611812576020820181803683370190505b5090505b841561189557611827600183611dd9565b9150611834600a866120a8565b61183f906030611e1f565b60f81b81838151811061185457611854611df0565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061188e600a86612065565b9450611816565b949350505050565b606060006118d484367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003611e1f565b90508267ffffffffffffffff1667ffffffffffffffff8111156118f9576118f9612079565b6040519080825280601f01601f191660200182016040528015611923576020820181803683370190505b509150828160208401375092915050565b6000806119c1837e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b600167ffffffffffffffff919091161b90920392915050565b6000806119f8846fffffffffffffffffffffffffffffffff16611a77565b905060018381548110611a0d57611a0d611df0565b906000526020600020906003020191505b60028201546fffffffffffffffffffffffffffffffff828116911614611a7057815460018054909163ffffffff16908110611a5b57611a5b611df0565b90600052602060002090600302019150611a1e565b5092915050565b60008119600183011681611b0b827e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff169390931c8015179392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160038310611b8d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60008060408385031215611ba657600080fd5b50508035926020909101359150565b60005b83811015611bd0578181015183820152602001611bb8565b83811115611bdf576000848401525b50505050565b60008151808452611bfd816020860160208601611bb5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611c426020830184611be5565b9392505050565b80358015158114611c5957600080fd5b919050565b600080600060608486031215611c7357600080fd5b8335925060208401359150611c8a60408501611c49565b90509250925092565b600060208284031215611ca557600080fd5b5035919050565b60008083601f840112611cbe57600080fd5b50813567ffffffffffffffff811115611cd657600080fd5b602083019150836020828501011115611cee57600080fd5b9250929050565b60008060008060008060808789031215611d0e57600080fd5b86359550611d1e60208801611c49565b9450604087013567ffffffffffffffff80821115611d3b57600080fd5b611d478a838b01611cac565b90965094506060890135915080821115611d6057600080fd5b50611d6d89828a01611cac565b979a9699509497509295939492505050565b60ff84168152826020820152606060408201526000611da16060830184611be5565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611deb57611deb611daa565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008219821115611e3257611e32611daa565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600067ffffffffffffffff80841680611e8157611e81611e37565b92169190910692915050565b60008451611e9f818460208901611bb5565b80830190507f2e000000000000000000000000000000000000000000000000000000000000008082528551611edb816001850160208a01611bb5565b60019201918201528351611ef6816002840160208801611bb5565b0160020195945050505050565b60006fffffffffffffffffffffffffffffffff83811690831681811015611f2c57611f2c611daa565b039392505050565b60006fffffffffffffffffffffffffffffffff808316818516808303821115611f5f57611f5f611daa565b01949350505050565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b604081526000611fd5604083018688611f78565b8281036020840152611fe8818587611f78565b979650505050505050565b60006020828403121561200557600080fd5b5051919050565b600067ffffffffffffffff83811690831681811015611f2c57611f2c611daa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361205e5761205e611daa565b5060010190565b60008261207457612074611e37565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000826120b7576120b7611e37565b50069056fea164736f6c634300080f000a",
} }
// FaultDisputeGameABI is the input ABI used to generate the binding from. // FaultDisputeGameABI is the input ABI used to generate the binding from.
......
...@@ -13,7 +13,7 @@ const FaultDisputeGameStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contr ...@@ -13,7 +13,7 @@ const FaultDisputeGameStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contr
var FaultDisputeGameStorageLayout = new(solc.StorageLayout) var FaultDisputeGameStorageLayout = new(solc.StorageLayout)
var FaultDisputeGameDeployedBin = "0x60806040526004361061016a5760003560e01c80638129fc1c116100cb578063bcef3b551161007f578063cf09e0d011610059578063cf09e0d01461049c578063d8cc1a3c146104bb578063fa24f743146104db57600080fd5b8063bcef3b55146103e8578063c55cd0c714610425578063c6f0308c1461043857600080fd5b80638b85902b116100b05780638b85902b146103585780639293129814610398578063bbdc02db146103cc57600080fd5b80638129fc1c1461032e5780638980e0cc1461034357600080fd5b8063363cc4271161012257806354fd4d501161010757806354fd4d50146102e4578063609d333414610306578063632247ea1461031b57600080fd5b8063363cc427146102515780634778efe8146102b057600080fd5b80632810e1d6116101535780632810e1d6146101ed5780633218b99d1461020257806335fef5671461023c57600080fd5b8063200d2ed21461016f578063266198f9146101ab575b600080fd5b34801561017b57600080fd5b506000546101959068010000000000000000900460ff1681565b6040516101a291906119e7565b60405180910390f35b3480156101b757600080fd5b506101df7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016101a2565b3480156101f957600080fd5b506101956104ff565b34801561020e57600080fd5b506000546102239067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101a2565b61024f61024a366004611a28565b6108f4565b005b34801561025d57600080fd5b5060005461028b906901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a2565b3480156102bc57600080fd5b506101df7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102f057600080fd5b506102f9610904565b6040516101a29190611ac4565b34801561031257600080fd5b506102f96109a7565b61024f610329366004611af3565b6109b9565b34801561033a57600080fd5b5061024f610f73565b34801561034f57600080fd5b506001546101df565b34801561036457600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003602001356101df565b3480156103a457600080fd5b5061028b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103d857600080fd5b50604051600081526020016101a2565b3480156103f457600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003356101df565b61024f610433366004611a28565b6110b4565b34801561044457600080fd5b50610458610453366004611b28565b6110c0565b6040805163ffffffff90961686529315156020860152928401919091526fffffffffffffffffffffffffffffffff908116606084015216608082015260a0016101a2565b3480156104a857600080fd5b5060005467ffffffffffffffff16610223565b3480156104c757600080fd5b5061024f6104d6366004611b8a565b611131565b3480156104e757600080fd5b506104f06114fb565b6040516101a293929190611c14565b60008060005468010000000000000000900460ff166002811115610525576105256119b8565b1461055c576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805460009161056c91611c6e565b90506fffffffffffffffffffffffffffffffff815b67ffffffffffffffff811015610656576000600182815481106105a6576105a6611c85565b6000918252602090912060039091020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019290915060ff64010000000090910416156105f75750610581565b600281015460009061063b906fffffffffffffffffffffffffffffffff167f0000000000000000000000000000000000000000000000000000000000000000611539565b90508381101561064f578093508260010194505b5050610581565b5060006001838154811061066c5761066c611c85565b600091825260208220600390910201805490925063ffffffff908116919082146106d657600182815481106106a3576106a3611c85565b906000526020600020906003020160020160109054906101000a90046fffffffffffffffffffffffffffffffff16610702565b600283015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff165b905062049d4061071c67ffffffffffffffff831642611c6e565b610738836fffffffffffffffffffffffffffffffff1660401c90565b67ffffffffffffffff1661074c9190611cb4565b11610783576040517ff2440b5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600283810154610825906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b61082f9190611cfb565b67ffffffffffffffff1615801561085657506fffffffffffffffffffffffffffffffff8414155b156108645760029550610869565b600195505b600080548791907fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000008360028111156108ae576108ae6119b8565b0217905560028111156108c3576108c36119b8565b6040517f5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da6090600090a2505050505090565b610900828260006109b9565b5050565b606061092f7f00000000000000000000000000000000000000000000000000000000000000006115ee565b6109587f00000000000000000000000000000000000000000000000000000000000000006115ee565b6109817f00000000000000000000000000000000000000000000000000000000000000006115ee565b60405160200161099393929190611d22565b604051602081830303815290604052905090565b60606109b460208061172b565b905090565b6000805468010000000000000000900460ff1660028111156109dd576109dd6119b8565b14610a14576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82158015610a20575080155b15610a57576040517fa42637bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060018481548110610a6c57610a6c611c85565b60009182526020918290206040805160a0810182526003909302909101805463ffffffff8116845260ff64010000000090910416151593830193909352600180840154918301919091526002909201546fffffffffffffffffffffffffffffffff80821660608401527001000000000000000000000000000000009091041660808201528154909250819086908110610b0757610b07611c85565b6000918252602082206003909102018054921515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff909316929092179091556060820151610b71906fffffffffffffffffffffffffffffffff1684151760011b90565b90507f0000000000000000000000000000000000000000000000000000000000000000610c30826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff161115610c72576040517f56f57b2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815160009063ffffffff90811614610cd2576001836000015163ffffffff1681548110610ca157610ca1611c85565b906000526020600020906003020160020160109054906101000a90046fffffffffffffffffffffffffffffffff1690505b608083015160009067ffffffffffffffff1667ffffffffffffffff1642610d0b846fffffffffffffffffffffffffffffffff1660401c90565b67ffffffffffffffff16610d1f9190611cb4565b610d299190611c6e565b905062049d4067ffffffffffffffff82161115610d72576040517f3381d11400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000604082901b421790506000610d93888660009182526020526040902090565b60008181526002602052604090205490915060ff1615610ddf576040517f80497e3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260026020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155815160a08101835263ffffffff808f1682529381018581528184018e81526fffffffffffffffffffffffffffffffff808d16606085019081528a82166080860190815286548088018855968a52945160039096027fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf68101805495511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000909616979099169690961793909317909655517fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf78401555190518416700100000000000000000000000000000000029316929092177fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf8909201919091555133918a918c917f9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be91a4505050505050505050565b600080547fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000164267ffffffffffffffff161781556040805160a08101825263ffffffff81526020810192909252600191908101610ff87ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe369081013560f01c90033590565b815260016020820152604001426fffffffffffffffffffffffffffffffff908116909152825460018181018555600094855260209485902084516003909302018054958501511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090961663ffffffff909316929092179490941781556040830151938101939093556060820151608090920151811670010000000000000000000000000000000002911617600290910155565b610900828260016109b9565b600181815481106110d057600080fd5b600091825260209091206003909102018054600182015460029092015463ffffffff8216935064010000000090910460ff1691906fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041685565b6000805468010000000000000000900460ff166002811115611155576111556119b8565b1461118c576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600187815481106111a1576111a1611c85565b6000918252602082206003919091020160028101549092506fffffffffffffffffffffffffffffffff16908715821760011b90506112007f00000000000000000000000000000000000000000000000000000000000000006001611cb4565b61129c826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff16146112dd576040517f5f53dd9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080891561136357611301836fffffffffffffffffffffffffffffffff166117c2565b67ffffffffffffffff1660000361133a577f00000000000000000000000000000000000000000000000000000000000000009150611358565b611355611348600186611d98565b865463ffffffff16611868565b91505b50600184015461137d565b8460010154915061137a8460016113489190611dc9565b90505b81898960405161138e929190611dfd565b6040518091039020146113cd576040517f696550ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517ff8e0cb96000000000000000000000000000000000000000000000000000000008152819073ffffffffffffffffffffffffffffffffffffffff7f0000000000000000000000000000000000000000000000000000000000000000169063f8e0cb9690611447908d908d908d908d90600401611e56565b6020604051808303816000875af1158015611466573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061148a9190611e88565b036114c1576040517ffb4e40dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505082547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff16640100000000179092555050505050505050565b6000367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90033560606115326109a7565b9050909192565b6000806115c6847e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1690508083036001841b600180831b0386831b17039250505092915050565b60608160000361163157505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b811561165b578061164581611ea1565b91506116549050600a83611ed9565b9150611635565b60008167ffffffffffffffff81111561167657611676611eed565b6040519080825280601f01601f1916602001820160405280156116a0576020820181803683370190505b5090505b8415611723576116b5600183611c6e565b91506116c2600a86611f1c565b6116cd906030611cb4565b60f81b8183815181106116e2576116e2611c85565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061171c600a86611ed9565b94506116a4565b949350505050565b6060600061176284367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003611cb4565b90508267ffffffffffffffff1667ffffffffffffffff81111561178757611787611eed565b6040519080825280601f01601f1916602001820160405280156117b1576020820181803683370190505b509150828160208401375092915050565b60008061184f837e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b600167ffffffffffffffff919091161b90920392915050565b600080611886846fffffffffffffffffffffffffffffffff1661190c565b905060006001848154811061189d5761189d611c85565b906000526020600020906003020190505b60028101546fffffffffffffffffffffffffffffffff83811691161461190057805460018054909163ffffffff169081106118eb576118eb611c85565b906000526020600020906003020190506118ae565b60010154949350505050565b600081196001830116816119a0827e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff169390931c8015179392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160038310611a22577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60008060408385031215611a3b57600080fd5b50508035926020909101359150565b60005b83811015611a65578181015183820152602001611a4d565b83811115611a74576000848401525b50505050565b60008151808452611a92816020860160208601611a4a565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611ad76020830184611a7a565b9392505050565b80358015158114611aee57600080fd5b919050565b600080600060608486031215611b0857600080fd5b8335925060208401359150611b1f60408501611ade565b90509250925092565b600060208284031215611b3a57600080fd5b5035919050565b60008083601f840112611b5357600080fd5b50813567ffffffffffffffff811115611b6b57600080fd5b602083019150836020828501011115611b8357600080fd5b9250929050565b60008060008060008060808789031215611ba357600080fd5b86359550611bb360208801611ade565b9450604087013567ffffffffffffffff80821115611bd057600080fd5b611bdc8a838b01611b41565b90965094506060890135915080821115611bf557600080fd5b50611c0289828a01611b41565b979a9699509497509295939492505050565b60ff84168152826020820152606060408201526000611c366060830184611a7a565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611c8057611c80611c3f565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008219821115611cc757611cc7611c3f565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600067ffffffffffffffff80841680611d1657611d16611ccc565b92169190910692915050565b60008451611d34818460208901611a4a565b80830190507f2e000000000000000000000000000000000000000000000000000000000000008082528551611d70816001850160208a01611a4a565b60019201918201528351611d8b816002840160208801611a4a565b0160020195945050505050565b60006fffffffffffffffffffffffffffffffff83811690831681811015611dc157611dc1611c3f565b039392505050565b60006fffffffffffffffffffffffffffffffff808316818516808303821115611df457611df4611c3f565b01949350505050565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b604081526000611e6a604083018688611e0d565b8281036020840152611e7d818587611e0d565b979650505050505050565b600060208284031215611e9a57600080fd5b5051919050565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203611ed257611ed2611c3f565b5060010190565b600082611ee857611ee8611ccc565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082611f2b57611f2b611ccc565b50069056fea164736f6c634300080f000a" var FaultDisputeGameDeployedBin = "0x60806040526004361061016a5760003560e01c80638129fc1c116100cb578063bcef3b551161007f578063cf09e0d011610059578063cf09e0d01461049c578063d8cc1a3c146104bb578063fa24f743146104db57600080fd5b8063bcef3b55146103e8578063c55cd0c714610425578063c6f0308c1461043857600080fd5b80638b85902b116100b05780638b85902b146103585780639293129814610398578063bbdc02db146103cc57600080fd5b80638129fc1c1461032e5780638980e0cc1461034357600080fd5b8063363cc4271161012257806354fd4d501161010757806354fd4d50146102e4578063609d333414610306578063632247ea1461031b57600080fd5b8063363cc427146102515780634778efe8146102b057600080fd5b80632810e1d6116101535780632810e1d6146101ed5780633218b99d1461020257806335fef5671461023c57600080fd5b8063200d2ed21461016f578063266198f9146101ab575b600080fd5b34801561017b57600080fd5b506000546101959068010000000000000000900460ff1681565b6040516101a29190611b52565b60405180910390f35b3480156101b757600080fd5b506101df7f000000000000000000000000000000000000000000000000000000000000000081565b6040519081526020016101a2565b3480156101f957600080fd5b506101956104ff565b34801561020e57600080fd5b506000546102239067ffffffffffffffff1681565b60405167ffffffffffffffff90911681526020016101a2565b61024f61024a366004611b93565b6108f4565b005b34801561025d57600080fd5b5060005461028b906901000000000000000000900473ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101a2565b3480156102bc57600080fd5b506101df7f000000000000000000000000000000000000000000000000000000000000000081565b3480156102f057600080fd5b506102f9610904565b6040516101a29190611c2f565b34801561031257600080fd5b506102f96109a7565b61024f610329366004611c5e565b6109b9565b34801561033a57600080fd5b5061024f610f73565b34801561034f57600080fd5b506001546101df565b34801561036457600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003602001356101df565b3480156103a457600080fd5b5061028b7f000000000000000000000000000000000000000000000000000000000000000081565b3480156103d857600080fd5b50604051600081526020016101a2565b3480156103f457600080fd5b50367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003356101df565b61024f610433366004611b93565b6110b4565b34801561044457600080fd5b50610458610453366004611c93565b6110c0565b6040805163ffffffff90961686529315156020860152928401919091526fffffffffffffffffffffffffffffffff908116606084015216608082015260a0016101a2565b3480156104a857600080fd5b5060005467ffffffffffffffff16610223565b3480156104c757600080fd5b5061024f6104d6366004611cf5565b611131565b3480156104e757600080fd5b506104f061166d565b6040516101a293929190611d7f565b60008060005468010000000000000000900460ff16600281111561052557610525611b23565b1461055c576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001805460009161056c91611dd9565b90506fffffffffffffffffffffffffffffffff815b67ffffffffffffffff811015610656576000600182815481106105a6576105a6611df0565b6000918252602090912060039091020180547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9093019290915060ff64010000000090910416156105f75750610581565b600281015460009061063b906fffffffffffffffffffffffffffffffff167f00000000000000000000000000000000000000000000000000000000000000006116ab565b90508381101561064f578093508260010194505b5050610581565b5060006001838154811061066c5761066c611df0565b600091825260208220600390910201805490925063ffffffff908116919082146106d657600182815481106106a3576106a3611df0565b906000526020600020906003020160020160109054906101000a90046fffffffffffffffffffffffffffffffff16610702565b600283015470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff165b905062049d4061071c67ffffffffffffffff831642611dd9565b610738836fffffffffffffffffffffffffffffffff1660401c90565b67ffffffffffffffff1661074c9190611e1f565b11610783576040517ff2440b5300000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600283810154610825906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b61082f9190611e66565b67ffffffffffffffff1615801561085657506fffffffffffffffffffffffffffffffff8414155b156108645760029550610869565b600195505b600080548791907fffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffff16680100000000000000008360028111156108ae576108ae611b23565b0217905560028111156108c3576108c3611b23565b6040517f5e186f09b9c93491f14e277eea7faa5de6a2d4bda75a79af7a3684fbfb42da6090600090a2505050505090565b610900828260006109b9565b5050565b606061092f7f0000000000000000000000000000000000000000000000000000000000000000611760565b6109587f0000000000000000000000000000000000000000000000000000000000000000611760565b6109817f0000000000000000000000000000000000000000000000000000000000000000611760565b60405160200161099393929190611e8d565b604051602081830303815290604052905090565b60606109b460208061189d565b905090565b6000805468010000000000000000900460ff1660028111156109dd576109dd611b23565b14610a14576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82158015610a20575080155b15610a57576040517fa42637bc00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600060018481548110610a6c57610a6c611df0565b60009182526020918290206040805160a0810182526003909302909101805463ffffffff8116845260ff64010000000090910416151593830193909352600180840154918301919091526002909201546fffffffffffffffffffffffffffffffff80821660608401527001000000000000000000000000000000009091041660808201528154909250819086908110610b0757610b07611df0565b6000918252602082206003909102018054921515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff909316929092179091556060820151610b71906fffffffffffffffffffffffffffffffff1684151760011b90565b90507f0000000000000000000000000000000000000000000000000000000000000000610c30826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff161115610c72576040517f56f57b2b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b815160009063ffffffff90811614610cd2576001836000015163ffffffff1681548110610ca157610ca1611df0565b906000526020600020906003020160020160109054906101000a90046fffffffffffffffffffffffffffffffff1690505b608083015160009067ffffffffffffffff1667ffffffffffffffff1642610d0b846fffffffffffffffffffffffffffffffff1660401c90565b67ffffffffffffffff16610d1f9190611e1f565b610d299190611dd9565b905062049d4067ffffffffffffffff82161115610d72576040517f3381d11400000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000604082901b421790506000610d93888660009182526020526040902090565b60008181526002602052604090205490915060ff1615610ddf576040517f80497e3b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081815260026020908152604080832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001908117909155815160a08101835263ffffffff808f1682529381018581528184018e81526fffffffffffffffffffffffffffffffff808d16606085019081528a82166080860190815286548088018855968a52945160039096027fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf68101805495511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000909616979099169690961793909317909655517fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf78401555190518416700100000000000000000000000000000000029316929092177fb10e2d527612073b26eecdfd717e6a320cf44b4afac2b0732d9fcbe2b7fa0cf8909201919091555133918a918c917f9b3245740ec3b155098a55be84957a4da13eaf7f14a8bc6f53126c0b9350f2be91a4505050505050505050565b600080547fffffffffffffffffffffffffffffffffffffffffffffff000000000000000000164267ffffffffffffffff161781556040805160a08101825263ffffffff81526020810192909252600191908101610ff87ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe369081013560f01c90033590565b815260016020820152604001426fffffffffffffffffffffffffffffffff908116909152825460018181018555600094855260209485902084516003909302018054958501511515640100000000027fffffffffffffffffffffffffffffffffffffffffffffffffffffff000000000090961663ffffffff909316929092179490941781556040830151938101939093556060820151608090920151811670010000000000000000000000000000000002911617600290910155565b610900828260016109b9565b600181815481106110d057600080fd5b600091825260209091206003909102018054600182015460029092015463ffffffff8216935064010000000090910460ff1691906fffffffffffffffffffffffffffffffff8082169170010000000000000000000000000000000090041685565b6000805468010000000000000000900460ff16600281111561115557611155611b23565b1461118c576040517f67fe195000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000600187815481106111a1576111a1611df0565b6000918252602082206003919091020160028101549092506fffffffffffffffffffffffffffffffff16908715821760011b90506112007f00000000000000000000000000000000000000000000000000000000000000006001611e1f565b61129c826fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff16146112dd576040517f5f53dd9800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600080891561136357611301836fffffffffffffffffffffffffffffffff16611934565b67ffffffffffffffff1660000361133a577f0000000000000000000000000000000000000000000000000000000000000000915061135c565b611355611348600186611f03565b865463ffffffff166119da565b6001015491505b508361137d565b8460010154915061137a8460016113489190611f34565b90505b81898960405161138e929190611f68565b6040518091039020146113cd576040517f696550ff00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600081600101547f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663f8e0cb968c8c8c8c6040518563ffffffff1660e01b81526004016114339493929190611fc1565b6020604051808303816000875af1158015611452573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114769190611ff3565b600284810154929091149250600091611521906fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b6115bd886fffffffffffffffffffffffffffffffff167e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b6115c7919061200c565b6115d19190611e66565b67ffffffffffffffff161590508080156115e85750815b806115fa5750801580156115fa575081155b15611631576040517ffb4e40dd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b505084547fffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffff166401000000001790945550505050505050505050565b6000367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c90033560606116a46109a7565b9050909192565b600080611738847e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff1690508083036001841b600180831b0386831b17039250505092915050565b6060816000036117a357505060408051808201909152600181527f3000000000000000000000000000000000000000000000000000000000000000602082015290565b8160005b81156117cd57806117b78161202d565b91506117c69050600a83612065565b91506117a7565b60008167ffffffffffffffff8111156117e8576117e8612079565b6040519080825280601f01601f191660200182016040528015611812576020820181803683370190505b5090505b841561189557611827600183611dd9565b9150611834600a866120a8565b61183f906030611e1f565b60f81b81838151811061185457611854611df0565b60200101907effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1916908160001a90535061188e600a86612065565b9450611816565b949350505050565b606060006118d484367ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe81013560f01c9003611e1f565b90508267ffffffffffffffff1667ffffffffffffffff8111156118f9576118f9612079565b6040519080825280601f01601f191660200182016040528015611923576020820181803683370190505b509150828160208401375092915050565b6000806119c1837e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b600167ffffffffffffffff919091161b90920392915050565b6000806119f8846fffffffffffffffffffffffffffffffff16611a77565b905060018381548110611a0d57611a0d611df0565b906000526020600020906003020191505b60028201546fffffffffffffffffffffffffffffffff828116911614611a7057815460018054909163ffffffff16908110611a5b57611a5b611df0565b90600052602060002090600302019150611a1e565b5092915050565b60008119600183011681611b0b827e09010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f7f07c4acdd0000000000000000000000000000000000000000000000000000000067ffffffffffffffff831160061b83811c63ffffffff1060051b1792831c600181901c17600281901c17600481901c17600881901c17601081901c170260fb1c1a1790565b67ffffffffffffffff169390931c8015179392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b6020810160038310611b8d577f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b91905290565b60008060408385031215611ba657600080fd5b50508035926020909101359150565b60005b83811015611bd0578181015183820152602001611bb8565b83811115611bdf576000848401525b50505050565b60008151808452611bfd816020860160208601611bb5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b602081526000611c426020830184611be5565b9392505050565b80358015158114611c5957600080fd5b919050565b600080600060608486031215611c7357600080fd5b8335925060208401359150611c8a60408501611c49565b90509250925092565b600060208284031215611ca557600080fd5b5035919050565b60008083601f840112611cbe57600080fd5b50813567ffffffffffffffff811115611cd657600080fd5b602083019150836020828501011115611cee57600080fd5b9250929050565b60008060008060008060808789031215611d0e57600080fd5b86359550611d1e60208801611c49565b9450604087013567ffffffffffffffff80821115611d3b57600080fd5b611d478a838b01611cac565b90965094506060890135915080821115611d6057600080fd5b50611d6d89828a01611cac565b979a9699509497509295939492505050565b60ff84168152826020820152606060408201526000611da16060830184611be5565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611deb57611deb611daa565b500390565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008219821115611e3257611e32611daa565b500190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b600067ffffffffffffffff80841680611e8157611e81611e37565b92169190910692915050565b60008451611e9f818460208901611bb5565b80830190507f2e000000000000000000000000000000000000000000000000000000000000008082528551611edb816001850160208a01611bb5565b60019201918201528351611ef6816002840160208801611bb5565b0160020195945050505050565b60006fffffffffffffffffffffffffffffffff83811690831681811015611f2c57611f2c611daa565b039392505050565b60006fffffffffffffffffffffffffffffffff808316818516808303821115611f5f57611f5f611daa565b01949350505050565b8183823760009101908152919050565b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b604081526000611fd5604083018688611f78565b8281036020840152611fe8818587611f78565b979650505050505050565b60006020828403121561200557600080fd5b5051919050565b600067ffffffffffffffff83811690831681811015611f2c57611f2c611daa565b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff820361205e5761205e611daa565b5060010190565b60008261207457612074611e37565b500490565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000826120b7576120b7611e37565b50069056fea164736f6c634300080f000a"
func init() { func init() {
if err := json.Unmarshal([]byte(FaultDisputeGameStorageLayoutJSON), FaultDisputeGameStorageLayout); err != nil { if err := json.Unmarshal([]byte(FaultDisputeGameStorageLayoutJSON), FaultDisputeGameStorageLayout); err != nil {
......
...@@ -31,7 +31,7 @@ var ( ...@@ -31,7 +31,7 @@ var (
// MIPSMetaData contains all meta data concerning the MIPS contract. // MIPSMetaData contains all meta data concerning the MIPS contract.
var MIPSMetaData = &bind.MetaData{ var MIPSMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[],\"name\":\"BRK_START\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracle\",\"outputs\":[{\"internalType\":\"contractIPreimageOracle\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"stateData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"step\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]", ABI: "[{\"inputs\":[],\"name\":\"BRK_START\",\"outputs\":[{\"internalType\":\"uint32\",\"name\":\"\",\"type\":\"uint32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"oracle\",\"outputs\":[{\"internalType\":\"contractIPreimageOracle\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"stateData\",\"type\":\"bytes\"},{\"internalType\":\"bytes\",\"name\":\"proof\",\"type\":\"bytes\"}],\"name\":\"step\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]",
Bin: "0x608060405234801561001057600080fd5b50611b21806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d014610067578063f8e0cb9614610098575b600080fd5b61004e61016c565b6040805163ffffffff9092168252519081900360200190f35b61006f610174565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61015a600480360360408110156100ae57600080fd5b8101906020810181356401000000008111156100c957600080fd5b8201836020820111156100db57600080fd5b803590602001918460018302840111640100000000831117156100fd57600080fd5b91939092909160208101903564010000000081111561011b57600080fd5b82018360208201111561012d57600080fd5b8035906020019184600183028401116401000000008311171561014f57600080fd5b509092509050610190565b60408051918252519081900360200190f35b634000000081565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600061019a611a67565b608081146101a757600080fd5b604051610600146101b757600080fd5b606486146101c457600080fd5b61016684146101d257600080fd5b6101ef565b8035602084810360031b9190911c8352920192910190565b8560806101fe602082846101d7565b9150915061020e602082846101d7565b9150915061021e600482846101d7565b9150915061022e600482846101d7565b9150915061023e600482846101d7565b9150915061024e600482846101d7565b9150915061025e600482846101d7565b9150915061026e600482846101d7565b9150915061027e600182846101d7565b9150915061028e600182846101d7565b9150915061029e600882846101d7565b6020810190819052909250905060005b60208110156102d0576102c3600483856101d7565b90935091506001016102ae565b505050806101200151156102ee576102e6610710565b915050610708565b6101408101805160010167ffffffffffffffff1690526060810151600090610316908261081e565b9050603f601a82901c16600281148061033557508063ffffffff166003145b15610382576103788163ffffffff1660021461035257601f610355565b60005b60ff16600261036b856303ffffff16601a6108e6565b63ffffffff16901b610959565b9350505050610708565b6101608301516000908190601f601086901c81169190601587901c16602081106103a857fe5b602002015192508063ffffffff851615806103c957508463ffffffff16601c145b156103fa578661016001518263ffffffff16602081106103e557fe5b6020020151925050601f600b86901c166104b1565b60208563ffffffff16101561045d578463ffffffff16600c148061042457508463ffffffff16600d145b8061043557508463ffffffff16600e145b15610446578561ffff169250610458565b6104558661ffff1660106108e6565b92505b6104b1565b60288563ffffffff1610158061047957508463ffffffff166022145b8061048a57508463ffffffff166026145b156104b1578661016001518263ffffffff16602081106104a657fe5b602002015192508190505b60048563ffffffff16101580156104ce575060088563ffffffff16105b806104df57508463ffffffff166001145b156104fe576104f0858784876109c4565b975050505050505050610708565b63ffffffff60006020878316106105635761051e8861ffff1660106108e6565b9095019463fffffffc861661053481600161081e565b915060288863ffffffff161015801561055457508763ffffffff16603014155b1561056157809250600093505b505b600061057189888885610b4d565b63ffffffff9081169150603f8a16908916158015610596575060088163ffffffff1610155b80156105a85750601c8163ffffffff16105b15610687578063ffffffff16600814806105c857508063ffffffff166009145b156105ff576105ed8163ffffffff166008146105e457856105e7565b60005b89610959565b9b505050505050505050505050610708565b8063ffffffff16600a1415610620576105ed858963ffffffff8a1615611213565b8063ffffffff16600b1415610642576105ed858963ffffffff8a161515611213565b8063ffffffff16600c1415610659576105ed6112f8565b60108163ffffffff16101580156106765750601c8163ffffffff16105b15610687576105ed81898988611775565b8863ffffffff1660381480156106a2575063ffffffff861615155b156106d15760018b61016001518763ffffffff16602081106106c057fe5b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146106ee576106ee84600184611959565b6106fa85836001611213565b9b5050505050505050505050505b949350505050565b6000610728565b602083810382015183520192910190565b60806040518061073a60208285610717565b9150925061074a60208285610717565b9150925061075a60048285610717565b9150925061076a60048285610717565b9150925061077a60048285610717565b9150925061078a60048285610717565b9150925061079a60048285610717565b915092506107aa60048285610717565b915092506107ba60018285610717565b915092506107ca60018285610717565b915092506107da60088285610717565b60209091019350905060005b6020811015610808576107fb60048386610717565b90945091506001016107e6565b506000815281810382a081900390209150505b90565b60008061082a836119f5565b9050600384161561083a57600080fd5b602081019035610857565b60009081526020919091526040902090565b8460051c8160005b601b8110156108af5760208501943583821c60011680156108875760018114610898576108a5565b6108918285610845565b93506108a5565b6108a28483610845565b93505b505060010161085f565b5060805191508181146108ca57630badf00d60005260206000fd5b5050601f8516601c0360031b1c63ffffffff1691505092915050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b0182610943576000610945565b815b90861663ffffffff16179250505092915050565b6000610963611a67565b5060e08051610100805163ffffffff90811690935284831690526080918516156109b357806008018261016001518663ffffffff16602081106109a257fe5b63ffffffff90921660209290920201525b6109bb610710565b95945050505050565b60006109ce611a67565b5060806000600463ffffffff881614806109ee57508663ffffffff166005145b15610a645760008261016001518663ffffffff1660208110610a0c57fe5b602002015190508063ffffffff168563ffffffff16148015610a3457508763ffffffff166004145b80610a5c57508063ffffffff168563ffffffff1614158015610a5c57508763ffffffff166005145b915050610ae1565b8663ffffffff1660061415610a825760008460030b13159050610ae1565b8663ffffffff1660071415610a9f5760008460030b139050610ae1565b8663ffffffff1660011415610ae157601f601087901c1680610ac55760008560030b1291505b8063ffffffff1660011415610adf5760008560030b121591505b505b606082018051608084015163ffffffff169091528115610b27576002610b0c8861ffff1660106108e6565b63ffffffff90811690911b8201600401166080840152610b39565b60808301805160040163ffffffff1690525b610b41610710565b98975050505050505050565b6000603f601a86901c81169086166020821015610f215760088263ffffffff1610158015610b815750600f8263ffffffff16105b15610c28578163ffffffff1660081415610b9d57506020610c23565b8163ffffffff1660091415610bb457506021610c23565b8163ffffffff16600a1415610bcb5750602a610c23565b8163ffffffff16600b1415610be25750602b610c23565b8163ffffffff16600c1415610bf957506024610c23565b8163ffffffff16600d1415610c1057506025610c23565b8163ffffffff16600e1415610c23575060265b600091505b63ffffffff8216610e7157601f600688901c16602063ffffffff83161015610d455760088263ffffffff1610610c6357869350505050610708565b63ffffffff8216610c835763ffffffff86811691161b9250610708915050565b8163ffffffff1660021415610ca75763ffffffff86811691161c9250610708915050565b8163ffffffff1660031415610cd2576103788163ffffffff168763ffffffff16901c826020036108e6565b8163ffffffff1660041415610cf6575050505063ffffffff8216601f84161b610708565b8163ffffffff1660061415610d1a575050505063ffffffff8216601f84161c610708565b8163ffffffff1660071415610d45576103788763ffffffff168763ffffffff16901c886020036108e6565b8163ffffffff1660201480610d6057508163ffffffff166021145b15610d72578587019350505050610708565b8163ffffffff1660221480610d8d57508163ffffffff166023145b15610d9f578587039350505050610708565b8163ffffffff1660241415610dbb578587169350505050610708565b8163ffffffff1660251415610dd7578587179350505050610708565b8163ffffffff1660261415610df3578587189350505050610708565b8163ffffffff1660271415610e0f575050505082821719610708565b8163ffffffff16602a1415610e42578560030b8760030b12610e32576000610e35565b60015b60ff169350505050610708565b8163ffffffff16602b1415610e6b578563ffffffff168763ffffffff1610610e32576000610e35565b50610f1c565b8163ffffffff16600f1415610e945760108563ffffffff16901b92505050610708565b8163ffffffff16601c1415610f1c578063ffffffff1660021415610ebd57505050828202610708565b8063ffffffff1660201480610ed857508063ffffffff166021145b15610f1c578063ffffffff1660201415610ef0579419945b60005b6380000000871615610f12576401fffffffe600197881b169601610ef3565b9250610708915050565b6111ac565b60288263ffffffff16101561108b578163ffffffff1660201415610f6e57610f658660031660080260180363ffffffff168563ffffffff16901c60ff1660086108e6565b92505050610708565b8163ffffffff1660211415610fa457610f658660021660080260100363ffffffff168563ffffffff16901c61ffff1660106108e6565b8163ffffffff1660221415610fd55750505063ffffffff60086003851602811681811b198416918316901b17610708565b8163ffffffff1660231415610fee578392505050610708565b8163ffffffff1660241415611022578560031660080260180363ffffffff168463ffffffff16901c60ff1692505050610708565b8163ffffffff1660251415611057578560021660080260100363ffffffff168463ffffffff16901c61ffff1692505050610708565b8163ffffffff1660261415610f1c5750505063ffffffff60086003851602601803811681811c198416918316901c17610708565b8163ffffffff16602814156110c35750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610708565b8163ffffffff16602914156110fc5750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610708565b8163ffffffff16602a141561112d5750505063ffffffff60086003851602811681811c198316918416901c17610708565b8163ffffffff16602b1415611146578492505050610708565b8163ffffffff16602e141561117a5750505063ffffffff60086003851602601803811681811b198316918416901b17610708565b8163ffffffff1660301415611193578392505050610708565b8163ffffffff16603814156111ac578492505050610708565b604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e00000000000000000000000000604482015290519081900360640190fd5b600061121d611a67565b506080602063ffffffff86161061129557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c6964207265676973746572000000000000000000000000000000000000604482015290519081900360640190fd5b63ffffffff8516158015906112a75750825b156112d557838161016001518663ffffffff16602081106112c457fe5b63ffffffff90921660209290920201525b60808101805163ffffffff808216606085015260049091011690526109bb610710565b6000611302611a67565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa141561137a5781610fff81161561134c57610fff811661100003015b63ffffffff84166113705760e08801805163ffffffff838201169091529550611374565b8395505b50611728565b8563ffffffff16610fcd14156113965763400000009450611728565b8563ffffffff1661101814156113af5760019450611728565b8563ffffffff1661109614156113e757600161012088015260ff83166101008801526113d9610710565b97505050505050505061081b565b8563ffffffff16610fa314156115a65763ffffffff8316611407576115a1565b63ffffffff83166005141561157e5760006114298363fffffffc16600161081e565b6000805460208b01516040808d015181517fe03110e1000000000000000000000000000000000000000000000000000000008152600481019390935263ffffffff16602483015280519495509293849373ffffffffffffffffffffffffffffffffffffffff9093169263e03110e19260448082019391829003018186803b1580156114b357600080fd5b505afa1580156114c7573d6000803e3d6000fd5b505050506040513d60408110156114dd57600080fd5b508051602090910151909250905060038516600481900382811015611500578092505b508185101561150d578491505b8260088302610100031c9250826008828460040301021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119861617945050506115648563fffffffc16600185611959565b60408a018051820163ffffffff16905296506115a1915050565b63ffffffff831660031415611595578094506115a1565b63ffffffff9450600993505b611728565b8563ffffffff16610fa4141561167a5763ffffffff8316600114806115d1575063ffffffff83166002145b806115e2575063ffffffff83166004145b156115ef578094506115a1565b63ffffffff8316600614156115955760006116118363fffffffc16600161081e565b6020890151909150600384166004038381101561162c578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b176020880152600060408801529350836115a1565b8563ffffffff16610fd71415611728578163ffffffff166003141561171c5763ffffffff831615806116b2575063ffffffff83166005145b806116c3575063ffffffff83166003145b156116d157600094506115a1565b63ffffffff8316600114806116ec575063ffffffff83166002145b806116fd575063ffffffff83166006145b8061170e575063ffffffff83166004145b1561159557600194506115a1565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b01526004019091169052611769610710565b97505050505050505090565b600061177f611a67565b5060806000601063ffffffff8816141561179e575060c08101516118f6565b8663ffffffff16601114156117be5763ffffffff861660c08301526118f6565b8663ffffffff16601214156117d8575060a08101516118f6565b8663ffffffff16601314156117f85763ffffffff861660a08301526118f6565b8663ffffffff166018141561182d5763ffffffff600387810b9087900b02602081901c821660c08501521660a08301526118f6565b8663ffffffff166019141561185f5763ffffffff86811681871602602081901c821660c08501521660a08301526118f6565b8663ffffffff16601a14156118aa578460030b8660030b8161187d57fe5b0763ffffffff1660c0830152600385810b9087900b8161189957fe5b0563ffffffff1660a08301526118f6565b8663ffffffff16601b14156118f6578463ffffffff168663ffffffff16816118ce57fe5b0663ffffffff90811660c0840152858116908716816118e957fe5b0463ffffffff1660a08301525b63ffffffff84161561192b57808261016001518563ffffffff166020811061191a57fe5b63ffffffff90921660209290920201525b60808201805163ffffffff8082166060860152600490910116905261194e610710565b979650505050505050565b6000611964836119f5565b9050600384161561197457600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b8110156119ea5760208401933582821c60011680156119c257600181146119d3576119e0565b6119cc8286610845565b94506119e0565b6119dd8583610845565b94505b505060010161199a565b505060805250505050565b60ff81166103800261016681019036906104e601811015611a61576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611af26023913960400191505060405180910390fd5b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611acd611ad2565b905290565b604051806104000160405280602090602082028036833750919291505056fe636865636b207468617420746865726520697320656e6f7567682063616c6c64617461a164736f6c6343000706000a", Bin: "0x608060405234801561001057600080fd5b50611b24806100206000396000f3fe608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d014610067578063f8e0cb9614610098575b600080fd5b61004e61016c565b6040805163ffffffff9092168252519081900360200190f35b61006f610174565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61015a600480360360408110156100ae57600080fd5b8101906020810181356401000000008111156100c957600080fd5b8201836020820111156100db57600080fd5b803590602001918460018302840111640100000000831117156100fd57600080fd5b91939092909160208101903564010000000081111561011b57600080fd5b82018360208201111561012d57600080fd5b8035906020019184600183028401116401000000008311171561014f57600080fd5b509092509050610190565b60408051918252519081900360200190f35b634000000081565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600061019a611a6a565b608081146101a757600080fd5b604051610600146101b757600080fd5b606486146101c457600080fd5b61016684146101d257600080fd5b6101ef565b8035602084810360031b9190911c8352920192910190565b8560806101fe602082846101d7565b9150915061020e602082846101d7565b9150915061021e600482846101d7565b9150915061022e600482846101d7565b9150915061023e600482846101d7565b9150915061024e600482846101d7565b9150915061025e600482846101d7565b9150915061026e600482846101d7565b9150915061027e600182846101d7565b9150915061028e600182846101d7565b9150915061029e600882846101d7565b6020810190819052909250905060005b60208110156102d0576102c3600483856101d7565b90935091506001016102ae565b505050806101200151156102ee576102e6610710565b915050610708565b6101408101805160010167ffffffffffffffff1690526060810151600090610316908261081e565b9050603f601a82901c16600281148061033557508063ffffffff166003145b15610382576103788163ffffffff1660021461035257601f610355565b60005b60ff16600261036b856303ffffff16601a6108e9565b63ffffffff16901b61095c565b9350505050610708565b6101608301516000908190601f601086901c81169190601587901c16602081106103a857fe5b602002015192508063ffffffff851615806103c957508463ffffffff16601c145b156103fa578661016001518263ffffffff16602081106103e557fe5b6020020151925050601f600b86901c166104b1565b60208563ffffffff16101561045d578463ffffffff16600c148061042457508463ffffffff16600d145b8061043557508463ffffffff16600e145b15610446578561ffff169250610458565b6104558661ffff1660106108e9565b92505b6104b1565b60288563ffffffff1610158061047957508463ffffffff166022145b8061048a57508463ffffffff166026145b156104b1578661016001518263ffffffff16602081106104a657fe5b602002015192508190505b60048563ffffffff16101580156104ce575060088563ffffffff16105b806104df57508463ffffffff166001145b156104fe576104f0858784876109c7565b975050505050505050610708565b63ffffffff60006020878316106105635761051e8861ffff1660106108e9565b9095019463fffffffc861661053481600161081e565b915060288863ffffffff161015801561055457508763ffffffff16603014155b1561056157809250600093505b505b600061057189888885610b50565b63ffffffff9081169150603f8a16908916158015610596575060088163ffffffff1610155b80156105a85750601c8163ffffffff16105b15610687578063ffffffff16600814806105c857508063ffffffff166009145b156105ff576105ed8163ffffffff166008146105e457856105e7565b60005b8961095c565b9b505050505050505050505050610708565b8063ffffffff16600a1415610620576105ed858963ffffffff8a1615611216565b8063ffffffff16600b1415610642576105ed858963ffffffff8a161515611216565b8063ffffffff16600c1415610659576105ed6112fb565b60108163ffffffff16101580156106765750601c8163ffffffff16105b15610687576105ed81898988611778565b8863ffffffff1660381480156106a2575063ffffffff861615155b156106d15760018b61016001518763ffffffff16602081106106c057fe5b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146106ee576106ee8460018461195c565b6106fa85836001611216565b9b5050505050505050505050505b949350505050565b6000610728565b602083810382015183520192910190565b60806040518061073a60208285610717565b9150925061074a60208285610717565b9150925061075a60048285610717565b9150925061076a60048285610717565b9150925061077a60048285610717565b9150925061078a60048285610717565b9150925061079a60048285610717565b915092506107aa60048285610717565b915092506107ba60018285610717565b915092506107ca60018285610717565b915092506107da60088285610717565b60209091019350905060005b6020811015610808576107fb60048386610717565b90945091506001016107e6565b506000815281810382a081900390209150505b90565b60008061082a836119f8565b9050600384161561083a57600080fd5b602081019035610857565b60009081526020919091526040902090565b8460051c8160005b601b8110156108af5760208501943583821c60011680156108875760018114610898576108a5565b6108918285610845565b93506108a5565b6108a28483610845565b93505b505060010161085f565b5060805191508181146108ca57630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b0182610946576000610948565b815b90861663ffffffff16179250505092915050565b6000610966611a6a565b5060e08051610100805163ffffffff90811690935284831690526080918516156109b657806008018261016001518663ffffffff16602081106109a557fe5b63ffffffff90921660209290920201525b6109be610710565b95945050505050565b60006109d1611a6a565b5060806000600463ffffffff881614806109f157508663ffffffff166005145b15610a675760008261016001518663ffffffff1660208110610a0f57fe5b602002015190508063ffffffff168563ffffffff16148015610a3757508763ffffffff166004145b80610a5f57508063ffffffff168563ffffffff1614158015610a5f57508763ffffffff166005145b915050610ae4565b8663ffffffff1660061415610a855760008460030b13159050610ae4565b8663ffffffff1660071415610aa25760008460030b139050610ae4565b8663ffffffff1660011415610ae457601f601087901c1680610ac85760008560030b1291505b8063ffffffff1660011415610ae25760008560030b121591505b505b606082018051608084015163ffffffff169091528115610b2a576002610b0f8861ffff1660106108e9565b63ffffffff90811690911b8201600401166080840152610b3c565b60808301805160040163ffffffff1690525b610b44610710565b98975050505050505050565b6000603f601a86901c81169086166020821015610f245760088263ffffffff1610158015610b845750600f8263ffffffff16105b15610c2b578163ffffffff1660081415610ba057506020610c26565b8163ffffffff1660091415610bb757506021610c26565b8163ffffffff16600a1415610bce5750602a610c26565b8163ffffffff16600b1415610be55750602b610c26565b8163ffffffff16600c1415610bfc57506024610c26565b8163ffffffff16600d1415610c1357506025610c26565b8163ffffffff16600e1415610c26575060265b600091505b63ffffffff8216610e7457601f600688901c16602063ffffffff83161015610d485760088263ffffffff1610610c6657869350505050610708565b63ffffffff8216610c865763ffffffff86811691161b9250610708915050565b8163ffffffff1660021415610caa5763ffffffff86811691161c9250610708915050565b8163ffffffff1660031415610cd5576103788163ffffffff168763ffffffff16901c826020036108e9565b8163ffffffff1660041415610cf9575050505063ffffffff8216601f84161b610708565b8163ffffffff1660061415610d1d575050505063ffffffff8216601f84161c610708565b8163ffffffff1660071415610d48576103788763ffffffff168763ffffffff16901c886020036108e9565b8163ffffffff1660201480610d6357508163ffffffff166021145b15610d75578587019350505050610708565b8163ffffffff1660221480610d9057508163ffffffff166023145b15610da2578587039350505050610708565b8163ffffffff1660241415610dbe578587169350505050610708565b8163ffffffff1660251415610dda578587179350505050610708565b8163ffffffff1660261415610df6578587189350505050610708565b8163ffffffff1660271415610e12575050505082821719610708565b8163ffffffff16602a1415610e45578560030b8760030b12610e35576000610e38565b60015b60ff169350505050610708565b8163ffffffff16602b1415610e6e578563ffffffff168763ffffffff1610610e35576000610e38565b50610f1f565b8163ffffffff16600f1415610e975760108563ffffffff16901b92505050610708565b8163ffffffff16601c1415610f1f578063ffffffff1660021415610ec057505050828202610708565b8063ffffffff1660201480610edb57508063ffffffff166021145b15610f1f578063ffffffff1660201415610ef3579419945b60005b6380000000871615610f15576401fffffffe600197881b169601610ef6565b9250610708915050565b6111af565b60288263ffffffff16101561108e578163ffffffff1660201415610f7157610f688660031660080260180363ffffffff168563ffffffff16901c60ff1660086108e9565b92505050610708565b8163ffffffff1660211415610fa757610f688660021660080260100363ffffffff168563ffffffff16901c61ffff1660106108e9565b8163ffffffff1660221415610fd85750505063ffffffff60086003851602811681811b198416918316901b17610708565b8163ffffffff1660231415610ff1578392505050610708565b8163ffffffff1660241415611025578560031660080260180363ffffffff168463ffffffff16901c60ff1692505050610708565b8163ffffffff166025141561105a578560021660080260100363ffffffff168463ffffffff16901c61ffff1692505050610708565b8163ffffffff1660261415610f1f5750505063ffffffff60086003851602601803811681811c198416918316901c17610708565b8163ffffffff16602814156110c65750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610708565b8163ffffffff16602914156110ff5750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610708565b8163ffffffff16602a14156111305750505063ffffffff60086003851602811681811c198316918416901c17610708565b8163ffffffff16602b1415611149578492505050610708565b8163ffffffff16602e141561117d5750505063ffffffff60086003851602601803811681811b198316918416901b17610708565b8163ffffffff1660301415611196578392505050610708565b8163ffffffff16603814156111af578492505050610708565b604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e00000000000000000000000000604482015290519081900360640190fd5b6000611220611a6a565b506080602063ffffffff86161061129857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c6964207265676973746572000000000000000000000000000000000000604482015290519081900360640190fd5b63ffffffff8516158015906112aa5750825b156112d857838161016001518663ffffffff16602081106112c757fe5b63ffffffff90921660209290920201525b60808101805163ffffffff808216606085015260049091011690526109be610710565b6000611305611a6a565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa141561137d5781610fff81161561134f57610fff811661100003015b63ffffffff84166113735760e08801805163ffffffff838201169091529550611377565b8395505b5061172b565b8563ffffffff16610fcd1415611399576340000000945061172b565b8563ffffffff1661101814156113b2576001945061172b565b8563ffffffff1661109614156113ea57600161012088015260ff83166101008801526113dc610710565b97505050505050505061081b565b8563ffffffff16610fa314156115a95763ffffffff831661140a576115a4565b63ffffffff83166005141561158157600061142c8363fffffffc16600161081e565b6000805460208b01516040808d015181517fe03110e1000000000000000000000000000000000000000000000000000000008152600481019390935263ffffffff16602483015280519495509293849373ffffffffffffffffffffffffffffffffffffffff9093169263e03110e19260448082019391829003018186803b1580156114b657600080fd5b505afa1580156114ca573d6000803e3d6000fd5b505050506040513d60408110156114e057600080fd5b508051602090910151909250905060038516600481900382811015611503578092505b5081851015611510578491505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119861617945050506115678563fffffffc1660018561195c565b60408a018051820163ffffffff16905296506115a4915050565b63ffffffff831660031415611598578094506115a4565b63ffffffff9450600993505b61172b565b8563ffffffff16610fa4141561167d5763ffffffff8316600114806115d4575063ffffffff83166002145b806115e5575063ffffffff83166004145b156115f2578094506115a4565b63ffffffff8316600614156115985760006116148363fffffffc16600161081e565b6020890151909150600384166004038381101561162f578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b176020880152600060408801529350836115a4565b8563ffffffff16610fd7141561172b578163ffffffff166003141561171f5763ffffffff831615806116b5575063ffffffff83166005145b806116c6575063ffffffff83166003145b156116d457600094506115a4565b63ffffffff8316600114806116ef575063ffffffff83166002145b80611700575063ffffffff83166006145b80611711575063ffffffff83166004145b1561159857600194506115a4565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b0152600401909116905261176c610710565b97505050505050505090565b6000611782611a6a565b5060806000601063ffffffff881614156117a1575060c08101516118f9565b8663ffffffff16601114156117c15763ffffffff861660c08301526118f9565b8663ffffffff16601214156117db575060a08101516118f9565b8663ffffffff16601314156117fb5763ffffffff861660a08301526118f9565b8663ffffffff16601814156118305763ffffffff600387810b9087900b02602081901c821660c08501521660a08301526118f9565b8663ffffffff16601914156118625763ffffffff86811681871602602081901c821660c08501521660a08301526118f9565b8663ffffffff16601a14156118ad578460030b8660030b8161188057fe5b0763ffffffff1660c0830152600385810b9087900b8161189c57fe5b0563ffffffff1660a08301526118f9565b8663ffffffff16601b14156118f9578463ffffffff168663ffffffff16816118d157fe5b0663ffffffff90811660c0840152858116908716816118ec57fe5b0463ffffffff1660a08301525b63ffffffff84161561192e57808261016001518563ffffffff166020811061191d57fe5b63ffffffff90921660209290920201525b60808201805163ffffffff80821660608601526004909101169052611951610710565b979650505050505050565b6000611967836119f8565b9050600384161561197757600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b8110156119ed5760208401933582821c60011680156119c557600181146119d6576119e3565b6119cf8286610845565b94506119e3565b6119e08583610845565b94505b505060010161199d565b505060805250505050565b60ff81166103800261016681019036906104e601811015611a64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611af56023913960400191505060405180910390fd5b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611ad0611ad5565b905290565b604051806104000160405280602090602082028036833750919291505056fe636865636b207468617420746865726520697320656e6f7567682063616c6c64617461a164736f6c6343000706000a",
} }
// MIPSABI is the input ABI used to generate the binding from. // MIPSABI is the input ABI used to generate the binding from.
......
...@@ -13,9 +13,9 @@ const MIPSStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"cont ...@@ -13,9 +13,9 @@ const MIPSStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contract\":\"cont
var MIPSStorageLayout = new(solc.StorageLayout) var MIPSStorageLayout = new(solc.StorageLayout)
var MIPSDeployedBin = "0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d014610067578063f8e0cb9614610098575b600080fd5b61004e61016c565b6040805163ffffffff9092168252519081900360200190f35b61006f610174565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61015a600480360360408110156100ae57600080fd5b8101906020810181356401000000008111156100c957600080fd5b8201836020820111156100db57600080fd5b803590602001918460018302840111640100000000831117156100fd57600080fd5b91939092909160208101903564010000000081111561011b57600080fd5b82018360208201111561012d57600080fd5b8035906020019184600183028401116401000000008311171561014f57600080fd5b509092509050610190565b60408051918252519081900360200190f35b634000000081565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600061019a611a67565b608081146101a757600080fd5b604051610600146101b757600080fd5b606486146101c457600080fd5b61016684146101d257600080fd5b6101ef565b8035602084810360031b9190911c8352920192910190565b8560806101fe602082846101d7565b9150915061020e602082846101d7565b9150915061021e600482846101d7565b9150915061022e600482846101d7565b9150915061023e600482846101d7565b9150915061024e600482846101d7565b9150915061025e600482846101d7565b9150915061026e600482846101d7565b9150915061027e600182846101d7565b9150915061028e600182846101d7565b9150915061029e600882846101d7565b6020810190819052909250905060005b60208110156102d0576102c3600483856101d7565b90935091506001016102ae565b505050806101200151156102ee576102e6610710565b915050610708565b6101408101805160010167ffffffffffffffff1690526060810151600090610316908261081e565b9050603f601a82901c16600281148061033557508063ffffffff166003145b15610382576103788163ffffffff1660021461035257601f610355565b60005b60ff16600261036b856303ffffff16601a6108e6565b63ffffffff16901b610959565b9350505050610708565b6101608301516000908190601f601086901c81169190601587901c16602081106103a857fe5b602002015192508063ffffffff851615806103c957508463ffffffff16601c145b156103fa578661016001518263ffffffff16602081106103e557fe5b6020020151925050601f600b86901c166104b1565b60208563ffffffff16101561045d578463ffffffff16600c148061042457508463ffffffff16600d145b8061043557508463ffffffff16600e145b15610446578561ffff169250610458565b6104558661ffff1660106108e6565b92505b6104b1565b60288563ffffffff1610158061047957508463ffffffff166022145b8061048a57508463ffffffff166026145b156104b1578661016001518263ffffffff16602081106104a657fe5b602002015192508190505b60048563ffffffff16101580156104ce575060088563ffffffff16105b806104df57508463ffffffff166001145b156104fe576104f0858784876109c4565b975050505050505050610708565b63ffffffff60006020878316106105635761051e8861ffff1660106108e6565b9095019463fffffffc861661053481600161081e565b915060288863ffffffff161015801561055457508763ffffffff16603014155b1561056157809250600093505b505b600061057189888885610b4d565b63ffffffff9081169150603f8a16908916158015610596575060088163ffffffff1610155b80156105a85750601c8163ffffffff16105b15610687578063ffffffff16600814806105c857508063ffffffff166009145b156105ff576105ed8163ffffffff166008146105e457856105e7565b60005b89610959565b9b505050505050505050505050610708565b8063ffffffff16600a1415610620576105ed858963ffffffff8a1615611213565b8063ffffffff16600b1415610642576105ed858963ffffffff8a161515611213565b8063ffffffff16600c1415610659576105ed6112f8565b60108163ffffffff16101580156106765750601c8163ffffffff16105b15610687576105ed81898988611775565b8863ffffffff1660381480156106a2575063ffffffff861615155b156106d15760018b61016001518763ffffffff16602081106106c057fe5b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146106ee576106ee84600184611959565b6106fa85836001611213565b9b5050505050505050505050505b949350505050565b6000610728565b602083810382015183520192910190565b60806040518061073a60208285610717565b9150925061074a60208285610717565b9150925061075a60048285610717565b9150925061076a60048285610717565b9150925061077a60048285610717565b9150925061078a60048285610717565b9150925061079a60048285610717565b915092506107aa60048285610717565b915092506107ba60018285610717565b915092506107ca60018285610717565b915092506107da60088285610717565b60209091019350905060005b6020811015610808576107fb60048386610717565b90945091506001016107e6565b506000815281810382a081900390209150505b90565b60008061082a836119f5565b9050600384161561083a57600080fd5b602081019035610857565b60009081526020919091526040902090565b8460051c8160005b601b8110156108af5760208501943583821c60011680156108875760018114610898576108a5565b6108918285610845565b93506108a5565b6108a28483610845565b93505b505060010161085f565b5060805191508181146108ca57630badf00d60005260206000fd5b5050601f8516601c0360031b1c63ffffffff1691505092915050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b0182610943576000610945565b815b90861663ffffffff16179250505092915050565b6000610963611a67565b5060e08051610100805163ffffffff90811690935284831690526080918516156109b357806008018261016001518663ffffffff16602081106109a257fe5b63ffffffff90921660209290920201525b6109bb610710565b95945050505050565b60006109ce611a67565b5060806000600463ffffffff881614806109ee57508663ffffffff166005145b15610a645760008261016001518663ffffffff1660208110610a0c57fe5b602002015190508063ffffffff168563ffffffff16148015610a3457508763ffffffff166004145b80610a5c57508063ffffffff168563ffffffff1614158015610a5c57508763ffffffff166005145b915050610ae1565b8663ffffffff1660061415610a825760008460030b13159050610ae1565b8663ffffffff1660071415610a9f5760008460030b139050610ae1565b8663ffffffff1660011415610ae157601f601087901c1680610ac55760008560030b1291505b8063ffffffff1660011415610adf5760008560030b121591505b505b606082018051608084015163ffffffff169091528115610b27576002610b0c8861ffff1660106108e6565b63ffffffff90811690911b8201600401166080840152610b39565b60808301805160040163ffffffff1690525b610b41610710565b98975050505050505050565b6000603f601a86901c81169086166020821015610f215760088263ffffffff1610158015610b815750600f8263ffffffff16105b15610c28578163ffffffff1660081415610b9d57506020610c23565b8163ffffffff1660091415610bb457506021610c23565b8163ffffffff16600a1415610bcb5750602a610c23565b8163ffffffff16600b1415610be25750602b610c23565b8163ffffffff16600c1415610bf957506024610c23565b8163ffffffff16600d1415610c1057506025610c23565b8163ffffffff16600e1415610c23575060265b600091505b63ffffffff8216610e7157601f600688901c16602063ffffffff83161015610d455760088263ffffffff1610610c6357869350505050610708565b63ffffffff8216610c835763ffffffff86811691161b9250610708915050565b8163ffffffff1660021415610ca75763ffffffff86811691161c9250610708915050565b8163ffffffff1660031415610cd2576103788163ffffffff168763ffffffff16901c826020036108e6565b8163ffffffff1660041415610cf6575050505063ffffffff8216601f84161b610708565b8163ffffffff1660061415610d1a575050505063ffffffff8216601f84161c610708565b8163ffffffff1660071415610d45576103788763ffffffff168763ffffffff16901c886020036108e6565b8163ffffffff1660201480610d6057508163ffffffff166021145b15610d72578587019350505050610708565b8163ffffffff1660221480610d8d57508163ffffffff166023145b15610d9f578587039350505050610708565b8163ffffffff1660241415610dbb578587169350505050610708565b8163ffffffff1660251415610dd7578587179350505050610708565b8163ffffffff1660261415610df3578587189350505050610708565b8163ffffffff1660271415610e0f575050505082821719610708565b8163ffffffff16602a1415610e42578560030b8760030b12610e32576000610e35565b60015b60ff169350505050610708565b8163ffffffff16602b1415610e6b578563ffffffff168763ffffffff1610610e32576000610e35565b50610f1c565b8163ffffffff16600f1415610e945760108563ffffffff16901b92505050610708565b8163ffffffff16601c1415610f1c578063ffffffff1660021415610ebd57505050828202610708565b8063ffffffff1660201480610ed857508063ffffffff166021145b15610f1c578063ffffffff1660201415610ef0579419945b60005b6380000000871615610f12576401fffffffe600197881b169601610ef3565b9250610708915050565b6111ac565b60288263ffffffff16101561108b578163ffffffff1660201415610f6e57610f658660031660080260180363ffffffff168563ffffffff16901c60ff1660086108e6565b92505050610708565b8163ffffffff1660211415610fa457610f658660021660080260100363ffffffff168563ffffffff16901c61ffff1660106108e6565b8163ffffffff1660221415610fd55750505063ffffffff60086003851602811681811b198416918316901b17610708565b8163ffffffff1660231415610fee578392505050610708565b8163ffffffff1660241415611022578560031660080260180363ffffffff168463ffffffff16901c60ff1692505050610708565b8163ffffffff1660251415611057578560021660080260100363ffffffff168463ffffffff16901c61ffff1692505050610708565b8163ffffffff1660261415610f1c5750505063ffffffff60086003851602601803811681811c198416918316901c17610708565b8163ffffffff16602814156110c35750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610708565b8163ffffffff16602914156110fc5750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610708565b8163ffffffff16602a141561112d5750505063ffffffff60086003851602811681811c198316918416901c17610708565b8163ffffffff16602b1415611146578492505050610708565b8163ffffffff16602e141561117a5750505063ffffffff60086003851602601803811681811b198316918416901b17610708565b8163ffffffff1660301415611193578392505050610708565b8163ffffffff16603814156111ac578492505050610708565b604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e00000000000000000000000000604482015290519081900360640190fd5b600061121d611a67565b506080602063ffffffff86161061129557604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c6964207265676973746572000000000000000000000000000000000000604482015290519081900360640190fd5b63ffffffff8516158015906112a75750825b156112d557838161016001518663ffffffff16602081106112c457fe5b63ffffffff90921660209290920201525b60808101805163ffffffff808216606085015260049091011690526109bb610710565b6000611302611a67565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa141561137a5781610fff81161561134c57610fff811661100003015b63ffffffff84166113705760e08801805163ffffffff838201169091529550611374565b8395505b50611728565b8563ffffffff16610fcd14156113965763400000009450611728565b8563ffffffff1661101814156113af5760019450611728565b8563ffffffff1661109614156113e757600161012088015260ff83166101008801526113d9610710565b97505050505050505061081b565b8563ffffffff16610fa314156115a65763ffffffff8316611407576115a1565b63ffffffff83166005141561157e5760006114298363fffffffc16600161081e565b6000805460208b01516040808d015181517fe03110e1000000000000000000000000000000000000000000000000000000008152600481019390935263ffffffff16602483015280519495509293849373ffffffffffffffffffffffffffffffffffffffff9093169263e03110e19260448082019391829003018186803b1580156114b357600080fd5b505afa1580156114c7573d6000803e3d6000fd5b505050506040513d60408110156114dd57600080fd5b508051602090910151909250905060038516600481900382811015611500578092505b508185101561150d578491505b8260088302610100031c9250826008828460040301021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119861617945050506115648563fffffffc16600185611959565b60408a018051820163ffffffff16905296506115a1915050565b63ffffffff831660031415611595578094506115a1565b63ffffffff9450600993505b611728565b8563ffffffff16610fa4141561167a5763ffffffff8316600114806115d1575063ffffffff83166002145b806115e2575063ffffffff83166004145b156115ef578094506115a1565b63ffffffff8316600614156115955760006116118363fffffffc16600161081e565b6020890151909150600384166004038381101561162c578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b176020880152600060408801529350836115a1565b8563ffffffff16610fd71415611728578163ffffffff166003141561171c5763ffffffff831615806116b2575063ffffffff83166005145b806116c3575063ffffffff83166003145b156116d157600094506115a1565b63ffffffff8316600114806116ec575063ffffffff83166002145b806116fd575063ffffffff83166006145b8061170e575063ffffffff83166004145b1561159557600194506115a1565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b01526004019091169052611769610710565b97505050505050505090565b600061177f611a67565b5060806000601063ffffffff8816141561179e575060c08101516118f6565b8663ffffffff16601114156117be5763ffffffff861660c08301526118f6565b8663ffffffff16601214156117d8575060a08101516118f6565b8663ffffffff16601314156117f85763ffffffff861660a08301526118f6565b8663ffffffff166018141561182d5763ffffffff600387810b9087900b02602081901c821660c08501521660a08301526118f6565b8663ffffffff166019141561185f5763ffffffff86811681871602602081901c821660c08501521660a08301526118f6565b8663ffffffff16601a14156118aa578460030b8660030b8161187d57fe5b0763ffffffff1660c0830152600385810b9087900b8161189957fe5b0563ffffffff1660a08301526118f6565b8663ffffffff16601b14156118f6578463ffffffff168663ffffffff16816118ce57fe5b0663ffffffff90811660c0840152858116908716816118e957fe5b0463ffffffff1660a08301525b63ffffffff84161561192b57808261016001518563ffffffff166020811061191a57fe5b63ffffffff90921660209290920201525b60808201805163ffffffff8082166060860152600490910116905261194e610710565b979650505050505050565b6000611964836119f5565b9050600384161561197457600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b8110156119ea5760208401933582821c60011680156119c257600181146119d3576119e0565b6119cc8286610845565b94506119e0565b6119dd8583610845565b94505b505060010161199a565b505060805250505050565b60ff81166103800261016681019036906104e601811015611a61576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611af26023913960400191505060405180910390fd5b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611acd611ad2565b905290565b604051806104000160405280602090602082028036833750919291505056fe636865636b207468617420746865726520697320656e6f7567682063616c6c64617461a164736f6c6343000706000a" var MIPSDeployedBin = "0x608060405234801561001057600080fd5b50600436106100415760003560e01c8063155633fe146100465780637dc0d1d014610067578063f8e0cb9614610098575b600080fd5b61004e61016c565b6040805163ffffffff9092168252519081900360200190f35b61006f610174565b6040805173ffffffffffffffffffffffffffffffffffffffff9092168252519081900360200190f35b61015a600480360360408110156100ae57600080fd5b8101906020810181356401000000008111156100c957600080fd5b8201836020820111156100db57600080fd5b803590602001918460018302840111640100000000831117156100fd57600080fd5b91939092909160208101903564010000000081111561011b57600080fd5b82018360208201111561012d57600080fd5b8035906020019184600183028401116401000000008311171561014f57600080fd5b509092509050610190565b60408051918252519081900360200190f35b634000000081565b60005473ffffffffffffffffffffffffffffffffffffffff1681565b600061019a611a6a565b608081146101a757600080fd5b604051610600146101b757600080fd5b606486146101c457600080fd5b61016684146101d257600080fd5b6101ef565b8035602084810360031b9190911c8352920192910190565b8560806101fe602082846101d7565b9150915061020e602082846101d7565b9150915061021e600482846101d7565b9150915061022e600482846101d7565b9150915061023e600482846101d7565b9150915061024e600482846101d7565b9150915061025e600482846101d7565b9150915061026e600482846101d7565b9150915061027e600182846101d7565b9150915061028e600182846101d7565b9150915061029e600882846101d7565b6020810190819052909250905060005b60208110156102d0576102c3600483856101d7565b90935091506001016102ae565b505050806101200151156102ee576102e6610710565b915050610708565b6101408101805160010167ffffffffffffffff1690526060810151600090610316908261081e565b9050603f601a82901c16600281148061033557508063ffffffff166003145b15610382576103788163ffffffff1660021461035257601f610355565b60005b60ff16600261036b856303ffffff16601a6108e9565b63ffffffff16901b61095c565b9350505050610708565b6101608301516000908190601f601086901c81169190601587901c16602081106103a857fe5b602002015192508063ffffffff851615806103c957508463ffffffff16601c145b156103fa578661016001518263ffffffff16602081106103e557fe5b6020020151925050601f600b86901c166104b1565b60208563ffffffff16101561045d578463ffffffff16600c148061042457508463ffffffff16600d145b8061043557508463ffffffff16600e145b15610446578561ffff169250610458565b6104558661ffff1660106108e9565b92505b6104b1565b60288563ffffffff1610158061047957508463ffffffff166022145b8061048a57508463ffffffff166026145b156104b1578661016001518263ffffffff16602081106104a657fe5b602002015192508190505b60048563ffffffff16101580156104ce575060088563ffffffff16105b806104df57508463ffffffff166001145b156104fe576104f0858784876109c7565b975050505050505050610708565b63ffffffff60006020878316106105635761051e8861ffff1660106108e9565b9095019463fffffffc861661053481600161081e565b915060288863ffffffff161015801561055457508763ffffffff16603014155b1561056157809250600093505b505b600061057189888885610b50565b63ffffffff9081169150603f8a16908916158015610596575060088163ffffffff1610155b80156105a85750601c8163ffffffff16105b15610687578063ffffffff16600814806105c857508063ffffffff166009145b156105ff576105ed8163ffffffff166008146105e457856105e7565b60005b8961095c565b9b505050505050505050505050610708565b8063ffffffff16600a1415610620576105ed858963ffffffff8a1615611216565b8063ffffffff16600b1415610642576105ed858963ffffffff8a161515611216565b8063ffffffff16600c1415610659576105ed6112fb565b60108163ffffffff16101580156106765750601c8163ffffffff16105b15610687576105ed81898988611778565b8863ffffffff1660381480156106a2575063ffffffff861615155b156106d15760018b61016001518763ffffffff16602081106106c057fe5b63ffffffff90921660209290920201525b8363ffffffff1663ffffffff146106ee576106ee8460018461195c565b6106fa85836001611216565b9b5050505050505050505050505b949350505050565b6000610728565b602083810382015183520192910190565b60806040518061073a60208285610717565b9150925061074a60208285610717565b9150925061075a60048285610717565b9150925061076a60048285610717565b9150925061077a60048285610717565b9150925061078a60048285610717565b9150925061079a60048285610717565b915092506107aa60048285610717565b915092506107ba60018285610717565b915092506107ca60018285610717565b915092506107da60088285610717565b60209091019350905060005b6020811015610808576107fb60048386610717565b90945091506001016107e6565b506000815281810382a081900390209150505b90565b60008061082a836119f8565b9050600384161561083a57600080fd5b602081019035610857565b60009081526020919091526040902090565b8460051c8160005b601b8110156108af5760208501943583821c60011680156108875760018114610898576108a5565b6108918285610845565b93506108a5565b6108a28483610845565b93505b505060010161085f565b5060805191508181146108ca57630badf00d60005260206000fd5b5050601f94909416601c0360031b9390931c63ffffffff169392505050565b600063ffffffff8381167fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80850183169190911c821615159160016020869003821681901b830191861691821b92911b0182610946576000610948565b815b90861663ffffffff16179250505092915050565b6000610966611a6a565b5060e08051610100805163ffffffff90811690935284831690526080918516156109b657806008018261016001518663ffffffff16602081106109a557fe5b63ffffffff90921660209290920201525b6109be610710565b95945050505050565b60006109d1611a6a565b5060806000600463ffffffff881614806109f157508663ffffffff166005145b15610a675760008261016001518663ffffffff1660208110610a0f57fe5b602002015190508063ffffffff168563ffffffff16148015610a3757508763ffffffff166004145b80610a5f57508063ffffffff168563ffffffff1614158015610a5f57508763ffffffff166005145b915050610ae4565b8663ffffffff1660061415610a855760008460030b13159050610ae4565b8663ffffffff1660071415610aa25760008460030b139050610ae4565b8663ffffffff1660011415610ae457601f601087901c1680610ac85760008560030b1291505b8063ffffffff1660011415610ae25760008560030b121591505b505b606082018051608084015163ffffffff169091528115610b2a576002610b0f8861ffff1660106108e9565b63ffffffff90811690911b8201600401166080840152610b3c565b60808301805160040163ffffffff1690525b610b44610710565b98975050505050505050565b6000603f601a86901c81169086166020821015610f245760088263ffffffff1610158015610b845750600f8263ffffffff16105b15610c2b578163ffffffff1660081415610ba057506020610c26565b8163ffffffff1660091415610bb757506021610c26565b8163ffffffff16600a1415610bce5750602a610c26565b8163ffffffff16600b1415610be55750602b610c26565b8163ffffffff16600c1415610bfc57506024610c26565b8163ffffffff16600d1415610c1357506025610c26565b8163ffffffff16600e1415610c26575060265b600091505b63ffffffff8216610e7457601f600688901c16602063ffffffff83161015610d485760088263ffffffff1610610c6657869350505050610708565b63ffffffff8216610c865763ffffffff86811691161b9250610708915050565b8163ffffffff1660021415610caa5763ffffffff86811691161c9250610708915050565b8163ffffffff1660031415610cd5576103788163ffffffff168763ffffffff16901c826020036108e9565b8163ffffffff1660041415610cf9575050505063ffffffff8216601f84161b610708565b8163ffffffff1660061415610d1d575050505063ffffffff8216601f84161c610708565b8163ffffffff1660071415610d48576103788763ffffffff168763ffffffff16901c886020036108e9565b8163ffffffff1660201480610d6357508163ffffffff166021145b15610d75578587019350505050610708565b8163ffffffff1660221480610d9057508163ffffffff166023145b15610da2578587039350505050610708565b8163ffffffff1660241415610dbe578587169350505050610708565b8163ffffffff1660251415610dda578587179350505050610708565b8163ffffffff1660261415610df6578587189350505050610708565b8163ffffffff1660271415610e12575050505082821719610708565b8163ffffffff16602a1415610e45578560030b8760030b12610e35576000610e38565b60015b60ff169350505050610708565b8163ffffffff16602b1415610e6e578563ffffffff168763ffffffff1610610e35576000610e38565b50610f1f565b8163ffffffff16600f1415610e975760108563ffffffff16901b92505050610708565b8163ffffffff16601c1415610f1f578063ffffffff1660021415610ec057505050828202610708565b8063ffffffff1660201480610edb57508063ffffffff166021145b15610f1f578063ffffffff1660201415610ef3579419945b60005b6380000000871615610f15576401fffffffe600197881b169601610ef6565b9250610708915050565b6111af565b60288263ffffffff16101561108e578163ffffffff1660201415610f7157610f688660031660080260180363ffffffff168563ffffffff16901c60ff1660086108e9565b92505050610708565b8163ffffffff1660211415610fa757610f688660021660080260100363ffffffff168563ffffffff16901c61ffff1660106108e9565b8163ffffffff1660221415610fd85750505063ffffffff60086003851602811681811b198416918316901b17610708565b8163ffffffff1660231415610ff1578392505050610708565b8163ffffffff1660241415611025578560031660080260180363ffffffff168463ffffffff16901c60ff1692505050610708565b8163ffffffff166025141561105a578560021660080260100363ffffffff168463ffffffff16901c61ffff1692505050610708565b8163ffffffff1660261415610f1f5750505063ffffffff60086003851602601803811681811c198416918316901c17610708565b8163ffffffff16602814156110c65750505060ff63ffffffff60086003861602601803811682811b9091188316918416901b17610708565b8163ffffffff16602914156110ff5750505061ffff63ffffffff60086002861602601003811682811b9091188316918416901b17610708565b8163ffffffff16602a14156111305750505063ffffffff60086003851602811681811c198316918416901c17610708565b8163ffffffff16602b1415611149578492505050610708565b8163ffffffff16602e141561117d5750505063ffffffff60086003851602601803811681811b198316918416901b17610708565b8163ffffffff1660301415611196578392505050610708565b8163ffffffff16603814156111af578492505050610708565b604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f696e76616c696420696e737472756374696f6e00000000000000000000000000604482015290519081900360640190fd5b6000611220611a6a565b506080602063ffffffff86161061129857604080517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f76616c6964207265676973746572000000000000000000000000000000000000604482015290519081900360640190fd5b63ffffffff8516158015906112aa5750825b156112d857838161016001518663ffffffff16602081106112c757fe5b63ffffffff90921660209290920201525b60808101805163ffffffff808216606085015260049091011690526109be610710565b6000611305611a6a565b506101e051604081015160808083015160a084015160c09094015191936000928392919063ffffffff8616610ffa141561137d5781610fff81161561134f57610fff811661100003015b63ffffffff84166113735760e08801805163ffffffff838201169091529550611377565b8395505b5061172b565b8563ffffffff16610fcd1415611399576340000000945061172b565b8563ffffffff1661101814156113b2576001945061172b565b8563ffffffff1661109614156113ea57600161012088015260ff83166101008801526113dc610710565b97505050505050505061081b565b8563ffffffff16610fa314156115a95763ffffffff831661140a576115a4565b63ffffffff83166005141561158157600061142c8363fffffffc16600161081e565b6000805460208b01516040808d015181517fe03110e1000000000000000000000000000000000000000000000000000000008152600481019390935263ffffffff16602483015280519495509293849373ffffffffffffffffffffffffffffffffffffffff9093169263e03110e19260448082019391829003018186803b1580156114b657600080fd5b505afa1580156114ca573d6000803e3d6000fd5b505050506040513d60408110156114e057600080fd5b508051602090910151909250905060038516600481900382811015611503578092505b5081851015611510578491505b8260088302610100031c9250826008828460040303021b9250600180600883600403021b036001806008858560040303021b039150811981169050838119861617945050506115678563fffffffc1660018561195c565b60408a018051820163ffffffff16905296506115a4915050565b63ffffffff831660031415611598578094506115a4565b63ffffffff9450600993505b61172b565b8563ffffffff16610fa4141561167d5763ffffffff8316600114806115d4575063ffffffff83166002145b806115e5575063ffffffff83166004145b156115f2578094506115a4565b63ffffffff8316600614156115985760006116148363fffffffc16600161081e565b6020890151909150600384166004038381101561162f578093505b83900360089081029290921c7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600193850293841b0116911b176020880152600060408801529350836115a4565b8563ffffffff16610fd7141561172b578163ffffffff166003141561171f5763ffffffff831615806116b5575063ffffffff83166005145b806116c6575063ffffffff83166003145b156116d457600094506115a4565b63ffffffff8316600114806116ef575063ffffffff83166002145b80611700575063ffffffff83166006145b80611711575063ffffffff83166004145b1561159857600194506115a4565b63ffffffff9450601693505b6101608701805163ffffffff808816604090920191909152905185821660e09091015260808801805180831660608b0152600401909116905261176c610710565b97505050505050505090565b6000611782611a6a565b5060806000601063ffffffff881614156117a1575060c08101516118f9565b8663ffffffff16601114156117c15763ffffffff861660c08301526118f9565b8663ffffffff16601214156117db575060a08101516118f9565b8663ffffffff16601314156117fb5763ffffffff861660a08301526118f9565b8663ffffffff16601814156118305763ffffffff600387810b9087900b02602081901c821660c08501521660a08301526118f9565b8663ffffffff16601914156118625763ffffffff86811681871602602081901c821660c08501521660a08301526118f9565b8663ffffffff16601a14156118ad578460030b8660030b8161188057fe5b0763ffffffff1660c0830152600385810b9087900b8161189c57fe5b0563ffffffff1660a08301526118f9565b8663ffffffff16601b14156118f9578463ffffffff168663ffffffff16816118d157fe5b0663ffffffff90811660c0840152858116908716816118ec57fe5b0463ffffffff1660a08301525b63ffffffff84161561192e57808261016001518563ffffffff166020811061191d57fe5b63ffffffff90921660209290920201525b60808201805163ffffffff80821660608601526004909101169052611951610710565b979650505050505050565b6000611967836119f8565b9050600384161561197757600080fd5b6020810190601f8516601c0360031b83811b913563ffffffff90911b1916178460051c60005b601b8110156119ed5760208401933582821c60011680156119c557600181146119d6576119e3565b6119cf8286610845565b94506119e3565b6119e08583610845565b94505b505060010161199d565b505060805250505050565b60ff81166103800261016681019036906104e601811015611a64576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401808060200182810382526023815260200180611af56023913960400191505060405180910390fd5b50919050565b6040805161018081018252600080825260208201819052918101829052606081018290526080810182905260a0810182905260c0810182905260e08101829052610100810182905261012081018290526101408101919091526101608101611ad0611ad5565b905290565b604051806104000160405280602090602082028036833750919291505056fe636865636b207468617420746865726520697320656e6f7567682063616c6c64617461a164736f6c6343000706000a"
var MIPSDeployedSourceMap = "1025:22415:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1423:45;;;:::i;:::-;;;;;;;;;;;;;;;;;;;1791:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;14376:4789;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;14376:4789:0;;-1:-1:-1;14376:4789:0;-1:-1:-1;14376:4789:0;:::i;:::-;;;;;;;;;;;;;;;;1423:45;1458:10;1423:45;:::o;1791:29::-;;;;;;:::o;14376:4789::-;14454:7;14469:18;;:::i;:::-;14569:4;14562:5;14559:15;14549:2;;14630:1;14628;14621:11;14549:2;14666:4;14660:11;14673;14657:28;14647:2;;14731:1;14729;14722:11;14647:2;14779:3;14761:16;14758:25;14748:2;;14845:1;14843;14836:11;14748:2;14889:3;14875:12;14872:21;14862:2;;14954:1;14952;14945:11;14862:2;14971:370;;;15189:24;;15177:2;15173:13;;;15170:1;15166:21;15162:52;;;;15223:20;;15269:21;;;15315:18;;;15049:292::o;:::-;15357:16;15408:4;15441:18;15456:2;15453:1;15450;15441:18;:::i;:::-;15433:26;;;;15485:18;15500:2;15497:1;15494;15485:18;:::i;:::-;15477:26;;;;15533:17;15548:1;15545;15542;15533:17;:::i;:::-;15525:25;;;;15583:17;15598:1;15595;15592;15583:17;:::i;:::-;15575:25;;;;15621:17;15636:1;15633;15630;15621:17;:::i;:::-;15613:25;;;;15663:17;15678:1;15675;15672;15663:17;:::i;:::-;15655:25;;;;15701:17;15716:1;15713;15710;15701:17;:::i;:::-;15693:25;;;;15739:17;15754:1;15751;15748;15739:17;:::i;:::-;15731:25;;;;15779:17;15794:1;15791;15788;15779:17;:::i;:::-;15771:25;;;;15823:17;15838:1;15835;15832;15823:17;:::i;:::-;15815:25;;;;15865:17;15880:1;15877;15874;15865:17;:::i;:::-;15914:2;15907:10;;15897:21;;;;15857:25;;-1:-1:-1;15907:10:0;-1:-1:-1;15985:1:0;15970:77;15995:2;15992:1;15989:9;15970:77;;;16028:17;16043:1;16040;16037;16028:17;:::i;:::-;16020:25;;-1:-1:-1;16020:25:0;-1:-1:-1;16013:1:0;16006:9;15970:77;;;15974:14;;;16074:5;:12;;;16071:86;;;16137:13;:11;:13::i;:::-;16130:20;;;;;16071:86;16162:10;;;:15;;16176:1;16162:15;;;;;16231:8;;;;-1:-1:-1;;16223:20:0;;-1:-1:-1;16223:7:0;:20::i;:::-;16209:34;-1:-1:-1;16266:10:0;16274:2;16266:10;;;;16327:1;16317:11;;;:26;;;16332:6;:11;;16342:1;16332:11;16317:26;16313:308;;;16552:62;16563:6;:11;;16573:1;16563:11;:20;;16581:2;16563:20;;;16577:1;16563:20;16552:62;;16612:1;16585:23;16588:4;16593:10;16588:15;16605:2;16585;:23::i;:::-;:28;;;;16552:10;:62::i;:::-;16545:69;;;;;;;16313:308;16822:15;;;;16649:9;;;;16770:4;16764:2;16756:10;;;16755:19;;;16822:15;16847:2;16839:10;;;16838:19;16822:36;;;;;;;;;;;;-1:-1:-1;16879:5:0;16894:11;;;;;:29;;;16909:6;:14;;16919:4;16909:14;16894:29;16890:636;;;16966:5;:15;;;16982:5;16966:22;;;;;;;;;;;;;;-1:-1:-1;;17019:4:0;17013:2;17005:10;;;17004:19;16890:636;;;17049:4;17040:6;:13;;;17036:490;;;17140:6;:13;;17150:3;17140:13;:30;;;;17157:6;:13;;17167:3;17157:13;17140:30;:47;;;;17174:6;:13;;17184:3;17174:13;17140:47;17136:181;;;17226:4;17231:6;17226:11;17221:16;;17136:181;;;17289:19;17292:4;17297:6;17292:11;17305:2;17289;:19::i;:::-;17284:24;;17136:181;17036:490;;;17343:4;17333:6;:14;;;;:32;;;;17351:6;:14;;17361:4;17351:14;17333:32;:50;;;;17369:6;:14;;17379:4;17369:14;17333:50;17329:197;;;17433:5;:15;;;17449:5;17433:22;;;;;;;;;;;;;17428:27;;17514:5;17506:13;;17329:197;17547:1;17537:6;:11;;;;:25;;;;;17561:1;17552:6;:10;;;17537:25;17536:42;;;;17567:6;:11;;17577:1;17567:11;17536:42;17532:107;;;17595:37;17608:6;17616:4;17622:5;17629:2;17595:12;:37::i;:::-;17588:44;;;;;;;;;;;17532:107;17664:13;17645:16;17784:4;17774:14;;;;17770:328;;17833:19;17836:4;17841:6;17836:11;17849:2;17833;:19::i;:::-;17827:25;;;;17879:10;17874:15;;17903:16;17874:15;17917:1;17903:7;:16::i;:::-;17897:22;;17941:4;17931:6;:14;;;;:32;;;;;17949:6;:14;;17959:4;17949:14;;17931:32;17927:165;;;18004:4;17992:16;;18082:1;18074:9;;17927:165;17770:328;;18115:10;18128:26;18136:4;18142:2;18146;18150:3;18128:7;:26::i;:::-;18157:10;18128:39;;;;-1:-1:-1;18245:4:0;18238:11;;;18269;;;:24;;;;;18292:1;18284:4;:9;;;;18269:24;:39;;;;;18304:4;18297;:11;;;18269:39;18265:589;;;18322:4;:9;;18330:1;18322:9;:22;;;;18335:4;:9;;18343:1;18335:9;18322:22;18318:102;;;18374:37;18385:4;:9;;18393:1;18385:9;:21;;18401:5;18385:21;;;18397:1;18385:21;18408:2;18374:10;:37::i;:::-;18367:44;;;;;;;;;;;;;;;18318:102;18432:4;:11;;18440:3;18432:11;18428:79;;;18470:28;18479:5;18486:2;18490:7;;;;18470:8;:28::i;18428:79::-;18518:4;:11;;18526:3;18518:11;18514:79;;;18556:28;18565:5;18572:2;18576:7;;;;;18556:8;:28::i;18514:79::-;18643:4;:11;;18651:3;18643:11;18639:58;;;18673:15;:13;:15::i;18639:58::-;18770:4;18762;:12;;;;:27;;;;;18785:4;18778;:11;;;18762:27;18758:90;;;18808:31;18819:4;18825:2;18829;18833:5;18808:10;:31::i;18758:90::-;18898:6;:14;;18908:4;18898:14;:28;;;;-1:-1:-1;18916:10:0;;;;;18898:28;18894:75;;;18961:1;18936:5;:15;;;18952:5;18936:22;;;;;;;;;:26;;;;:22;;;;;;:26;18894:75;18999:9;:26;;19012:13;18999:26;18995:74;;19035:27;19044:9;19055:1;19058:3;19035:8;:27::i;:::-;19134:26;19143:5;19150:3;19155:4;19134:8;:26::i;:::-;19127:33;;;;;;;;;;;;;14376:4789;;;;;;;:::o;2085:1331::-;2126:11;2254:176;;;2346:2;2342:13;;;2332:24;;2326:31;2315:43;;2378:13;;2409;;;2305:125::o;:::-;2449:4;2488;2482:11;2526:5;2550:21;2568:2;2564;2558:4;2550:21;:::i;:::-;2538:33;;;;2601:21;2619:2;2615;2609:4;2601:21;:::i;:::-;2589:33;;;;2656:20;2674:1;2670:2;2664:4;2656:20;:::i;:::-;2644:32;;;;2713:20;2731:1;2727:2;2721:4;2713:20;:::i;:::-;2701:32;;;;2758:20;2776:1;2772:2;2766:4;2758:20;:::i;:::-;2746:32;;;;2807:20;2825:1;2821:2;2815:4;2807:20;:::i;:::-;2795:32;;;;2852:20;2870:1;2866:2;2860:4;2852:20;:::i;:::-;2840:32;;;;2897:20;2915:1;2911:2;2905:4;2897:20;:::i;:::-;2885:32;;;;2944:20;2962:1;2958:2;2952:4;2944:20;:::i;:::-;2932:32;;;;2995:20;3013:1;3009:2;3003:4;2995:20;:::i;:::-;2983:32;;;;3044:20;3062:1;3058:2;3052:4;3044:20;:::i;:::-;3097:2;3087:13;;;;-1:-1:-1;3032:32:0;-1:-1:-1;3145:1:0;3130:84;3155:2;3152:1;3149:9;3130:84;;;3192:20;3210:1;3206:2;3200:4;3192:20;:::i;:::-;3180:32;;-1:-1:-1;3180:32:0;-1:-1:-1;3173:1:0;3166:9;3130:84;;;3134:14;3245:1;3241:2;3234:13;3290:5;3286:2;3282:14;3275:5;3270:27;3375:14;;;3358:32;;;-1:-1:-1;;2085:1331:0;;:::o;11778:1270::-;11849:10;11867:14;11884:23;11896:10;11884:11;:23::i;:::-;11867:40;;11943:1;11937:4;11933:12;11930:2;;;11958:1;11955;11948:12;11930:2;12060;12048:15;;;12011:20;12070:169;;;;12109:12;;;12195:2;12188:13;;;;12228:2;12215:16;;;12099:140::o;:::-;12265:4;12262:1;12258:12;12289:4;12412:1;12397:273;12422:2;12419:1;12416:9;12397:273;;;12521:2;12509:15;;;12470:20;12544:12;;;12558:1;12540:20;12569:42;;;;12625:1;12620:42;;;;12533:129;;12569:42;12586:23;12601:7;12595:4;12586:23;:::i;:::-;12578:31;;12569:42;;12620;12637:23;12655:4;12646:7;12637:23;:::i;:::-;12629:31;;12533:129;-1:-1:-1;;12440:1:0;12433:9;12397:273;;;12401:14;12698:4;12692:11;12677:26;;12767:7;12761:4;12758:17;12748:2;;12824:10;12821:1;12814:21;12854:2;12851:1;12844:13;12748:2;-1:-1:-1;;12970:2:0;12960:13;;12948:10;12944:30;12941:1;12937:38;12993:16;13011:10;12989:33;;-1:-1:-1;;11778:1270:0;;;;:::o;1825:256::-;1884:6;1915:14;;;;1923:5;;;;1915:14;;;;;;1914:21;;;;;1927:1;1966:2;:6;;;1960:13;;;;;1959:19;;1958:28;;;;;;;2008:8;;2007:14;1914:21;2053;;2073:1;2053:21;;;2064:6;2053:21;2041:8;;;;;:34;;-1:-1:-1;;;1825:256:0;;;;:::o;10450:401::-;10517:7;10532:18;;:::i;:::-;-1:-1:-1;10613:8:0;;;10638:12;;;10627:23;;;;;;;10656:19;;;;;10582:4;;10685:12;;;10681:140;;10734:6;10741:1;10734:8;10707:5;:15;;;10723:7;10707:24;;;;;;;;;:35;;;;:24;;;;;;:35;10681:140;10833:13;:11;:13::i;:::-;10826:20;10450:401;-1:-1:-1;;;;;10450:401:0:o;8292:1063::-;8385:7;8400:18;;:::i;:::-;-1:-1:-1;8450:4:0;8465:17;8511:1;8501:11;;;;;:26;;;8516:6;:11;;8526:1;8516:11;8501:26;8497:514;;;8550:9;8562:5;:15;;;8578:5;8562:22;;;;;;;;;;;;;8550:34;;8614:2;8608:8;;:2;:8;;;:23;;;;;8620:6;:11;;8630:1;8620:11;8608:23;8607:54;;;;8643:2;8637:8;;:2;:8;;;;:23;;;;;8649:6;:11;;8659:1;8649:11;8637:23;8592:69;;8497:514;;;;8678:6;:11;;8688:1;8678:11;8674:337;;;8721:1;8714:2;8708:14;;;;8693:29;;8674:337;;;8747:6;:11;;8757:1;8747:11;8743:268;;;8789:1;8783:2;8777:13;;;8762:28;;8743:268;;;8815:6;:11;;8825:1;8815:11;8811:200;;;8881:4;8875:2;8867:10;;;8866:19;8898:8;8894:42;;8935:1;8929:2;8923:13;;;8908:28;;8894:42;8957:3;:8;;8964:1;8957:8;8953:43;;;8995:1;8988:2;8982:14;;;;8967:29;;8953:43;8811:200;;9033:8;;;;;9058:12;;;;9047:23;;;;;9108:216;;;;9184:1;9163:19;9166:4;9171:6;9166:11;9179:2;9163;:19::i;:::-;:22;;;;;;;9149:37;;9158:1;9149:37;9134:52;:12;;;:52;9108:216;;;9281:12;;;;;9296:1;9281:16;9266:31;;;;9108:216;9337:13;:11;:13::i;:::-;9330:20;8292:1063;-1:-1:-1;;;;;;;;8292:1063:0:o;19169:4269::-;19256:6;19286:10;19294:2;19286:10;;;;;;19329:11;;19425:4;19416:13;;19412:3986;;;19526:1;19516:6;:11;;;;:27;;;;;19540:3;19531:6;:12;;;19516:27;19512:462;;;19559:6;:11;;19569:1;19559:11;19555:383;;;-1:-1:-1;19581:4:0;19555:383;;;19621:6;:11;;19631:1;19621:11;19617:321;;;-1:-1:-1;19643:4:0;19617:321;;;19679:6;:13;;19689:3;19679:13;19675:263;;;-1:-1:-1;19703:4:0;19675:263;;;19736:6;:13;;19746:3;19736:13;19732:206;;;-1:-1:-1;19760:4:0;19732:206;;;19794:6;:13;;19804:3;19794:13;19790:148;;;-1:-1:-1;19818:4:0;19790:148;;;19851:6;:13;;19861:3;19851:13;19847:91;;;-1:-1:-1;19875:4:0;19847:91;;;19907:6;:13;;19917:3;19907:13;19903:35;;;-1:-1:-1;19931:4:0;19903:35;19964:1;19955:10;;19512:462;20015:11;;;20011:1701;;20067:4;20062:1;20054:9;;;20053:18;20092:4;20054:9;20085:11;;;20081:588;;;20122:4;20114;:12;;;20110:549;;20137:2;20130:9;;;;;;;20110:549;20217:12;;;20213:446;;20240:11;;;;;;;;-1:-1:-1;20233:18:0;;-1:-1:-1;;20233:18:0;20213:446;20286:4;:12;;20294:4;20286:12;20282:377;;;20309:11;;;;;;;;-1:-1:-1;20302:18:0;;-1:-1:-1;;20302:18:0;20282:377;20355:4;:12;;20363:4;20355:12;20351:308;;;20378:25;20387:5;20381:11;;:2;:11;;;;20397:5;20394:2;:8;20378:2;:25::i;20351:308::-;20438:4;:12;;20446:4;20438:12;20434:225;;;-1:-1:-1;;;;20461:15:0;;;20471:4;20468:7;;20461:15;20454:22;;20434:225;20515:4;:12;;20523:4;20515:12;20511:148;;;-1:-1:-1;;;;20538:15:0;;;20548:4;20545:7;;20538:15;20531:22;;20511:148;20592:4;:12;;20600:4;20592:12;20588:71;;;20615:19;20624:2;20618:8;;:2;:8;;;;20631:2;20628;:5;20615:2;:19::i;20588:71::-;20757:4;:12;;20765:4;20757:12;:28;;;;20773:4;:12;;20781:4;20773:12;20757:28;20753:602;;;20799:2;20796;:5;20789:12;;;;;;;20753:602;20839:4;:12;;20847:4;20839:12;:28;;;;20855:4;:12;;20863:4;20855:12;20839:28;20835:520;;;20881:2;20878;:5;20871:12;;;;;;;20835:520;20921:4;:12;;20929:4;20921:12;20917:438;;;20947:2;20944;:5;20937:12;;;;;;;20917:438;20988:4;:12;;20996:4;20988:12;20984:371;;;21015:2;21012;:5;21004:14;;;;;;;20984:371;21054:4;:12;;21062:4;21054:12;21050:305;;;21081:2;21078;:5;21070:14;;;;;;;21050:305;21121:4;:12;;21129:4;21121:12;21117:238;;;-1:-1:-1;;;;21146:5:0;;;21144:8;21137:15;;21117:238;21188:4;:12;;21196:4;21188:12;21184:171;;;21237:2;21221:19;;21227:2;21221:19;;;:27;;21247:1;21221:27;;;21243:1;21221:27;21214:34;;;;;;;;;21184:171;21276:4;:12;;21284:4;21276:12;21272:83;;;21312:2;21309:5;;:2;:5;;;:13;;21321:1;21309:13;;21272:83;20011:1701;;;;21373:6;:13;;21383:3;21373:13;21369:343;;;21401:2;21397;:6;;;;21390:13;;;;;;21369:343;21429:6;:14;;21439:4;21429:14;21425:287;;;21472:4;:9;;21480:1;21472:9;21468:49;;;-1:-1:-1;;;21497:19:0;;;21483:34;;21468:49;21538:4;:12;;21546:4;21538:12;:28;;;;21554:4;:12;;21562:4;21554:12;21538:28;21534:170;;;21591:4;:12;;21599:4;21591:12;21587:26;;;21610:3;;;21587:26;21625:8;21639:45;21649:10;21646:13;;:18;21639:45;;21673:8;21668:3;21673:8;;;;;21668:3;21639:45;;;21692:1;-1:-1:-1;21685:8:0;;-1:-1:-1;;21685:8:0;21534:170;19412:3986;;;21737:4;21728:6;:13;;;21724:1674;;;21755:6;:14;;21765:4;21755:14;21751:776;;;21795:36;21811:2;21814:1;21811:4;21817:1;21810:8;21807:2;:11;21799:20;;:3;:20;;;;21823:4;21798:29;21829:1;21795:2;:36::i;:::-;21788:43;;;;;;21751:776;21850:6;:14;;21860:4;21850:14;21846:681;;;21890:39;21906:2;21909:1;21906:4;21912:1;21905:8;21902:2;:11;21894:20;;:3;:20;;;;21918:6;21893:31;21926:2;21890;:39::i;21846:681::-;21948:6;:14;;21958:4;21948:14;21944:583;;;-1:-1:-1;;;21995:17:0;22010:1;22007;22004:4;;22003:8;21995:17;;22036:32;;;22091:5;22086:10;;21995:17;;;;;22085:18;22078:25;;21944:583;22122:6;:14;;22132:4;22122:14;22118:409;;;22147:3;22140:10;;;;;;22118:409;22177:6;:14;;22187:4;22177:14;22173:354;;;22231:2;22234:1;22231:4;22237:1;22230:8;22227:2;:11;22219:20;;:3;:20;;;;22243:4;22218:29;22211:36;;;;;;22173:354;22266:6;:14;;22276:4;22266:14;22262:265;;;22320:2;22323:1;22320:4;22326:1;22319:8;22316:2;:11;22308:20;;:3;:20;;;;22332:6;22307:31;22300:38;;;;;;22262:265;22357:6;:14;;22367:4;22357:14;22353:174;;;-1:-1:-1;;;22404:20:0;22422:1;22419;22416:4;;22415:8;22412:2;:11;22404:20;;22448:35;;;22506:5;22501:10;;22404:20;;;;;22500:18;22493:25;;21724:1674;22543:6;:14;;22553:4;22543:14;22539:859;;;-1:-1:-1;;;22590:4:0;22586:26;22610:1;22607;22604:4;;22603:8;22600:2;:11;22586:26;;22654:21;;;22634:42;;;22692:10;;22587:7;;;22586:26;;22691:18;22684:25;;22539:859;22726:6;:14;;22736:4;22726:14;22722:676;;;-1:-1:-1;;;22773:6:0;22769:28;22795:1;22792;22789:4;;22788:8;22785:2;:11;22769:28;;22839:23;;;22819:44;;;22879:10;;22770:9;;;22769:28;;22878:18;22871:25;;22722:676;22913:6;:14;;22923:4;22913:14;22909:489;;;-1:-1:-1;;;22958:16:0;22972:1;22969;22966:4;;22965:8;22958:16;;22996:32;;;23050:5;23044:11;;22958:16;;;;;23043:19;23036:26;;22909:489;23079:6;:14;;23089:4;23079:14;23075:323;;;23116:2;23109:9;;;;;;23075:323;23135:6;:14;;23145:4;23135:14;23131:267;;;-1:-1:-1;;;23180:19:0;23197:1;23194;23191:4;;23190:8;23187:2;:11;23180:19;;23221:35;;;23278:5;23272:11;;23180:19;;;;;23271;23264:26;;23131:267;23307:6;:14;;23317:4;23307:14;23303:95;;;23332:3;23325:10;;;;;;23303:95;23358:6;:14;;23368:4;23358:14;23354:44;;;23383:2;23376:9;;;;;;23354:44;23404:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;10855:455;10938:7;10953:18;;:::i;:::-;-1:-1:-1;11003:4:0;11037:2;11026:13;;;;11018:40;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11136:13;;;;;;;:28;;;11153:11;11136:28;11132:80;;;11202:3;11174:5;:15;;;11190:8;11174:25;;;;;;;;;:31;;;;:25;;;;;;:31;11132:80;11229:12;;;;;11218:23;;;;:8;;;:23;11277:1;11262:16;;;11247:31;;;11292:13;:11;:13::i;3420:4868::-;3463:7;3478:18;;:::i;:::-;-1:-1:-1;3563:15:0;;:18;;;;3528:4;3638:18;;;;3674;;;;3710;;;;;3528:4;;3543:17;;;;3638:18;3674;3739;;;3753:4;3739:18;3735:4396;;;3793:2;3810:4;3807:7;;:12;3803:98;;3887:4;3884:7;;3876:4;:16;3870:22;3803:98;3912:7;;;3908:105;;3936:10;;;;;3956:16;;;;;;;;3936:10;-1:-1:-1;3908:105:0;;;4002:2;3997:7;;3908:105;3735:4396;;;;4029:10;:18;;4043:4;4029:18;4025:4106;;;1458:10;4070:14;;4025:4106;;;4101:10;:18;;4115:4;4101:18;4097:4034;;;4165:1;4160:6;;4097:4034;;;4183:10;:18;;4197:4;4183:18;4179:3952;;;4246:4;4231:12;;;:19;4258:26;;;:14;;;:26;4299:13;:11;:13::i;:::-;4292:20;;;;;;;;;;;4179:3952;4329:10;:18;;4343:4;4329:18;4325:3806;;;4458:14;;;4454:1789;;;;;4549:22;;;1679:1;4549:22;4545:1698;;;4670:10;4683:27;4691:2;4696:10;4691:15;4708:1;4683:7;:27::i;:::-;4761:11;4792:6;;4812:17;;;;4831:20;;;;;4792:60;;;;;;;;;;;;;;;;;;;;4670:40;;-1:-1:-1;4761:11:0;;;;4792:6;;;;;:19;;:60;;;;;;;;;;;:6;:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4792:60:0;;;;;;;;;-1:-1:-1;4792:60:0;-1:-1:-1;4965:1:0;4957:10;;5045:1;5041:17;;;5106;;;5103:2;;;5136:5;5126:15;;5103:2;;5205:6;5201:2;5198:14;5195:2;;;5225;5215:12;;5195:2;5317:3;5312:1;5304:6;5300:14;5295:3;5291:24;5287:34;5280:41;;5403:3;5399:1;5387:9;5378:6;5375:1;5371:14;5367:30;5363:38;5359:48;5352:55;;5513:1;5509;5505;5493:9;5490:1;5486:17;5482:25;5478:33;5474:41;5626:1;5622;5618;5609:6;5597:9;5594:1;5590:17;5586:30;5582:38;5578:46;5574:54;5556:72;;5712:10;5708:15;5702:4;5698:26;5690:34;;5814:3;5806:4;5802:9;5797:3;5793:19;5790:28;5783:35;;;;5894:33;5903:2;5908:10;5903:15;5920:1;5923:3;5894:8;:33::i;:::-;5937:20;;;:38;;;;;;;;;-1:-1:-1;4545:1698:0;;-1:-1:-1;;4545:1698:0;;6023:18;;;1602:1;6023:18;6019:224;;;6172:2;6167:7;;6019:224;;;6204:10;6199:15;;1750:3;6224:10;;6019:224;4325:3806;;;6259:10;:18;;6273:4;6259:18;6255:1876;;;6392:15;;;1533:1;6392:15;;:34;;-1:-1:-1;6411:15:0;;;1566:1;6411:15;6392:34;:57;;;-1:-1:-1;6430:19:0;;;1639:1;6430:19;6392:57;6388:1172;;;6466:2;6461:7;;6388:1172;;;6530:23;;;1720:1;6530:23;6526:1034;;;6585:10;6598:27;6606:2;6611:10;6606:15;6623:1;6598:7;:27::i;:::-;6689:17;;;;6585:40;;-1:-1:-1;6819:1:0;6811:10;;6899:1;6895:17;6960:13;;;6957:2;;;6982:5;6976:11;;6957:2;7226:14;;;7060:1;7222:22;;;7218:32;;;;7129:26;7153:1;7052:10;;;7133:18;;;7129:26;7214:43;7048:20;;7308:12;7358:17;;;:23;7414:1;7391:20;;;:24;7056:2;-1:-1:-1;7056:2:0;6526:1034;;6255:1876;7576:10;:18;;7590:4;7576:18;7572:559;;;7650:2;:7;;7656:1;7650:7;7646:479;;;7711:14;;;;;:40;;-1:-1:-1;7729:22:0;;;1679:1;7729:22;7711:40;:62;;;-1:-1:-1;7755:18:0;;;1602:1;7755:18;7711:62;7707:312;;;7792:1;7787:6;;7707:312;;;7826:15;;;1533:1;7826:15;;:34;;-1:-1:-1;7845:15:0;;;1566:1;7845:15;7826:34;:61;;;-1:-1:-1;7864:23:0;;;1720:1;7864:23;7826:61;:84;;;-1:-1:-1;7891:19:0;;;1639:1;7891:19;7826:84;7822:197;;;7929:1;7924:6;;7822:197;;7646:479;8048:10;8043:15;;1782:4;8068:11;;7646:479;8137:15;;;;;:23;;;;:18;;;;:23;;;;8166:15;;:23;;;:18;;;;:23;-1:-1:-1;8207:12:0;;;;8196:23;;;:8;;;:23;8255:1;8240:16;8225:31;;;;;8270:13;:11;:13::i;:::-;8263:20;;;;;;;;;3420:4868;:::o;9359:1087::-;9449:7;9464:18;;:::i;:::-;-1:-1:-1;9514:4:0;9529:10;9557:4;9549:12;;;;9545:732;;;-1:-1:-1;9569:8:0;;;;9545:732;;;9600:4;:12;;9608:4;9600:12;9596:681;;;9614:13;;;:8;;;:13;9596:681;;;9650:4;:12;;9658:4;9650:12;9646:631;;;-1:-1:-1;9670:8:0;;;;9646:631;;;9701:4;:12;;9709:4;9701:12;9697:580;;;9715:13;;;:8;;;:13;9697:580;;;9751:4;:12;;9759:4;9751:12;9747:530;;;9861:7;9818:16;9801;;;9818;;;;9801:33;9866:2;9861:7;;;;;9843:8;;;:26;9877:22;:8;;;:22;9747:530;;;9916:4;:12;;9924:4;9916:12;9912:365;;;9978:10;9967;;;9978;;;9967:21;10020:2;10015:7;;;;;9997:8;;;:26;10031:22;:8;;;:22;9912:365;;;10070:4;:12;;10078:4;10070:12;10066:211;;;10133:2;10117:19;;10123:2;10117:19;;;;;;;;10099:38;;:8;;;:38;10163:19;;;;;;;;;;;;;;10145:38;;:8;;;:38;10066:211;;;10200:4;:12;;10208:4;10200:12;10196:81;;;10244:2;10241:5;;:2;:5;;;;;;;;10230:16;;;;:8;;;:16;10265:5;;;;;;;;;;;;10254:16;;:8;;;:16;10196:81;10287:13;;;;10283:65;;10338:3;10310:5;:15;;;10326:8;10310:25;;;;;;;;;:31;;;;:25;;;;;;:31;10283:65;10365:12;;;;;10354:23;;;;:8;;;:23;10413:1;10398:16;;;10383:31;;;10428:13;:11;:13::i;:::-;10421:20;9359:1087;-1:-1:-1;;;;;;;9359:1087:0:o;13171:1145::-;13254:14;13271:23;13283:10;13271:11;:23::i;:::-;13254:40;;13330:1;13324:4;13320:12;13317:2;;;13345:1;13342;13335:12;13317:2;13453;13616:15;;;13471:2;13461:13;;13449:10;13445:30;13442:1;13438:38;13581:17;;;13398:20;;13566:10;13555:22;;;13551:27;13541:38;13538:61;13833:4;13830:1;13826:12;13980:1;13965:273;13990:2;13987:1;13984:9;13965:273;;;14089:2;14077:15;;;14038:20;14112:12;;;14126:1;14108:20;14137:42;;;;14193:1;14188:42;;;;14101:129;;14137:42;14154:23;14169:7;14163:4;14154:23;:::i;:::-;14146:31;;14137:42;;14188;14205:23;14223:4;14214:7;14205:23;:::i;:::-;14197:31;;14101:129;-1:-1:-1;;14008:1:0;14001:9;13965:273;;;-1:-1:-1;;14252:4:0;14245:18;-1:-1:-1;;;;13309:1003:0:o;11314:460::-;11589:19;;;11612:5;11589:29;11582:3;:37;;;11660:14;;11695;;11689:21;;;11681:69;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11756:13;11314:460;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o" var MIPSDeployedSourceMap = "1075:32558:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1655:45;;;:::i;:::-;;;;;;;;;;;;;;;;;;;2081:29;;;:::i;:::-;;;;;;;;;;;;;;;;;;;21344:5721;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;21344:5721:0;;-1:-1:-1;21344:5721:0;-1:-1:-1;21344:5721:0;:::i;:::-;;;;;;;;;;;;;;;;1655:45;1690:10;1655:45;:::o;2081:29::-;;;;;;:::o;21344:5721::-;21422:7;21441:18;;:::i;:::-;21576:4;21569:5;21566:15;21556:2;;21645:1;21643;21636:11;21556:2;21693:4;21687:11;21700;21684:28;21674:2;;21766:1;21764;21757:11;21674:2;21826:3;21808:16;21805:25;21795:2;;21900:1;21898;21891:11;21795:2;21956:3;21942:12;21939:21;21929:2;;22029:1;22027;22020:11;21929:2;22059:416;;;22293:24;;22281:2;22277:13;;;22274:1;22270:21;22266:52;;;;22335:20;;22389:21;;;22443:18;;;22137:338::o;:::-;22552:16;22610:4;22662:18;22677:2;22674:1;22671;22662:18;:::i;:::-;22654:26;;;;22712:18;22727:2;22724:1;22721;22712:18;:::i;:::-;22704:26;;;;22766:17;22781:1;22778;22775;22766:17;:::i;:::-;22758:25;;;;22823:17;22838:1;22835;22832;22823:17;:::i;:::-;22815:25;;;;22868:17;22883:1;22880;22877;22868:17;:::i;:::-;22860:25;;;;22917:17;22932:1;22929;22926;22917:17;:::i;:::-;22909:25;;;;22962:17;22977:1;22974;22971;22962:17;:::i;:::-;22954:25;;;;23007:17;23022:1;23019;23016;23007:17;:::i;:::-;22999:25;;;;23054:17;23069:1;23066;23063;23054:17;:::i;:::-;23046:25;;;;23105:17;23120:1;23117;23114;23105:17;:::i;:::-;23097:25;;;;23154:17;23169:1;23166;23163;23154:17;:::i;:::-;23263:2;23256:10;;23246:21;;;;23146:25;;-1:-1:-1;23256:10:0;-1:-1:-1;23351:1:0;23336:105;23361:2;23358:1;23355:9;23336:105;;;23410:17;23425:1;23422;23419;23410:17;:::i;:::-;23402:25;;-1:-1:-1;23402:25:0;-1:-1:-1;23379:1:0;23372:9;23336:105;;;23340:14;;;23507:5;:12;;;23503:63;;;23542:13;:11;:13::i;:::-;23535:20;;;;;23503:63;23576:10;;;:15;;23590:1;23576:15;;;;;23653:8;;;;-1:-1:-1;;23645:20:0;;-1:-1:-1;23645:7:0;:20::i;:::-;23631:34;-1:-1:-1;23691:10:0;23699:2;23691:10;;;;23760:1;23750:11;;;:26;;;23765:6;:11;;23775:1;23765:11;23750:26;23746:332;;;24003:64;24014:6;:11;;24024:1;24014:11;:20;;24032:2;24014:20;;;24028:1;24014:20;24003:64;;24065:1;24036:25;24039:4;24046:10;24039:17;24058:2;24036;:25::i;:::-;:30;;;;24003:10;:64::i;:::-;23996:71;;;;;;;23746:332;24303:15;;;;24114:9;;;;24243:4;24237:2;24229:10;;;24228:19;;;24303:15;24328:2;24320:10;;;24319:19;24303:36;;;;;;;;;;;;-1:-1:-1;24364:5:0;24384:11;;;;;:29;;;24399:6;:14;;24409:4;24399:14;24384:29;24380:756;;;24468:5;:15;;;24484:5;24468:22;;;;;;;;;;;;;;-1:-1:-1;;24527:4:0;24521:2;24513:10;;;24512:19;24380:756;;;24561:4;24552:6;:13;;;24548:588;;;24670:6;:13;;24680:3;24670:13;:30;;;;24687:6;:13;;24697:3;24687:13;24670:30;:47;;;;24704:6;:13;;24714:3;24704:13;24670:47;24666:229;;;24772:4;24779:6;24772:13;24767:18;;24666:229;;;24859:21;24862:4;24869:6;24862:13;24877:2;24859;:21::i;:::-;24854:26;;24666:229;24548:588;;;24925:4;24915:6;:14;;;;:32;;;;24933:6;:14;;24943:4;24933:14;24915:32;:50;;;;24951:6;:14;;24961:4;24951:14;24915:50;24911:225;;;25027:5;:15;;;25043:5;25027:22;;;;;;;;;;;;;25022:27;;25120:5;25112:13;;24911:225;25161:1;25151:6;:11;;;;:25;;;;;25175:1;25166:6;:10;;;25151:25;25150:42;;;;25181:6;:11;;25191:1;25181:11;25150:42;25146:117;;;25215:37;25228:6;25236:4;25242:5;25249:2;25215:12;:37::i;:::-;25208:44;;;;;;;;;;;25146:117;25292:13;25273:16;25428:4;25418:14;;;;25414:400;;25489:19;25492:4;25497:6;25492:11;25505:2;25489;:19::i;:::-;25483:25;;;;25541:10;25536:15;;25571:16;25536:15;25585:1;25571:7;:16::i;:::-;25565:22;;25615:4;25605:6;:14;;;;:32;;;;;25623:6;:14;;25633:4;25623:14;;25605:32;25601:203;;;25694:4;25682:16;;25788:1;25780:9;;25601:203;25414:400;;25839:10;25852:26;25860:4;25866:2;25870;25874:3;25852:7;:26::i;:::-;25881:10;25852:39;;;;-1:-1:-1;25973:4:0;25966:11;;;26001;;;:24;;;;;26024:1;26016:4;:9;;;;26001:24;:39;;;;;26036:4;26029;:11;;;26001:39;25997:711;;;26060:4;:9;;26068:1;26060:9;:22;;;;26073:4;:9;;26081:1;26073:9;26060:22;26056:116;;;26120:37;26131:4;:9;;26139:1;26131:9;:21;;26147:5;26131:21;;;26143:1;26131:21;26154:2;26120:10;:37::i;:::-;26113:44;;;;;;;;;;;;;;;26056:116;26190:4;:11;;26198:3;26190:11;26186:93;;;26236:28;26245:5;26252:2;26256:7;;;;26236:8;:28::i;26186:93::-;26296:4;:11;;26304:3;26296:11;26292:93;;;26342:28;26351:5;26358:2;26362:7;;;;;26342:8;:28::i;26292:93::-;26447:4;:11;;26455:3;26447:11;26443:72;;;26485:15;:13;:15::i;26443:72::-;26606:4;26598;:12;;;;:27;;;;;26621:4;26614;:11;;;26598:27;26594:104;;;26652:31;26663:4;26669:2;26673;26677:5;26652:10;:31::i;26594:104::-;26760:6;:14;;26770:4;26760:14;:28;;;;-1:-1:-1;26778:10:0;;;;;26760:28;26756:85;;;26829:1;26804:5;:15;;;26820:5;26804:22;;;;;;;;;:26;;;;:22;;;;;;:26;26756:85;26879:9;:26;;26892:13;26879:26;26875:84;;26921:27;26930:9;26941:1;26944:3;26921:8;:27::i;:::-;27032:26;27041:5;27048:3;27053:4;27032:8;:26::i;:::-;27025:33;;;;;;;;;;;;;21344:5721;;;;;;;:::o;2597:1791::-;2638:12;2783:206;;;2883:2;2879:13;;;2869:24;;2863:31;2852:43;;2923:13;;2962;;;2834:155::o;:::-;3060:4;3144;3138:11;3172:5;3244:21;3262:2;3258;3252:4;3244:21;:::i;:::-;3232:33;;;;3302:21;3320:2;3316;3310:4;3302:21;:::i;:::-;3290:33;;;;3364:20;3382:1;3378:2;3372:4;3364:20;:::i;:::-;3352:32;;;;3429:20;3447:1;3443:2;3437:4;3429:20;:::i;:::-;3417:32;;;;3482:20;3500:1;3496:2;3490:4;3482:20;:::i;:::-;3470:32;;;;3539:20;3557:1;3553:2;3547:4;3539:20;:::i;:::-;3527:32;;;;3592:20;3610:1;3606:2;3600:4;3592:20;:::i;:::-;3580:32;;;;3645:20;3663:1;3659:2;3653:4;3645:20;:::i;:::-;3633:32;;;;3700:20;3718:1;3714:2;3708:4;3700:20;:::i;:::-;3688:32;;;;3759:20;3777:1;3773:2;3767:4;3759:20;:::i;:::-;3747:32;;;;3816:20;3834:1;3830:2;3824:4;3816:20;:::i;:::-;3877:2;3867:13;;;;-1:-1:-1;3804:32:0;-1:-1:-1;3975:1:0;3960:112;3985:2;3982:1;3979:9;3960:112;;;4038:20;4056:1;4052:2;4046:4;4038:20;:::i;:::-;4026:32;;-1:-1:-1;4026:32:0;-1:-1:-1;4003:1:0;3996:9;3960:112;;;3964:14;4135:1;4131:2;4124:13;4230:5;4226:2;4222:14;4215:5;4210:27;4336:14;;;4319:32;;;-1:-1:-1;;2597:1791:0;;:::o;17559:1741::-;17632:11;17715:14;17732:24;17744:11;17732;:24::i;:::-;17715:41;;17852:1;17845:5;17841:13;17838:2;;;17883:1;17880;17873:12;17838:2;18016;18004:15;;;17961:20;18114:141;;;;18161:12;;;18197:2;18190:13;;;;18238:2;18225:16;;;18143:112::o;:::-;18410:5;18407:1;18403:13;18441:4;18473:1;18458:375;18483:2;18480:1;18477:9;18458:375;;;18598:2;18586:15;;;18539:20;18629:12;;;18643:1;18625:20;18662:78;;;;18746:1;18741:78;;;;18618:201;;18662:78;18699:23;18714:7;18708:4;18699:23;:::i;:::-;18691:31;;18662:78;;18741;18778:23;18796:4;18787:7;18778:23;:::i;:::-;18770:31;;18618:201;-1:-1:-1;;18501:1:0;18494:9;18458:375;;;18462:14;18935:4;18929:11;18914:26;;19013:7;19007:4;19004:17;18994:2;;19051:10;19048:1;19041:21;19089:2;19086:1;19079:13;18994:2;-1:-1:-1;;19225:2:0;19214:14;;;;19202:10;19198:31;19195:1;19191:39;19255:16;;;;19273:10;19251:33;;17776:1518;-1:-1:-1;;;17776:1518:0:o;2209:280::-;2268:6;2303:16;;;;2311:7;;;;2303:16;;;;;;2302:23;;;;;2317:1;2360:2;:8;;;2354:15;;;;;2353:21;;2352:30;;;;;;;2408:8;;2407:14;2302:23;2459:21;;2479:1;2459:21;;;2470:6;2459:21;2445:10;;;;;:36;;-1:-1:-1;;;2209:280:0;;;;:::o;15048:624::-;15117:12;15176:18;;:::i;:::-;-1:-1:-1;15331:8:0;;;15360:12;;;15349:23;;;;;;;15382:20;;;;;15236:4;;15506:13;;;15502:82;;15563:6;15572:1;15563:10;15535:5;:15;;;15551:8;15535:25;;;;;;;;;:38;;;;:25;;;;;;:38;15502:82;15652:13;:11;:13::i;:::-;15645:20;15048:624;-1:-1:-1;;;;;15048:624:0:o;10480:1713::-;10577:12;10635:18;;:::i;:::-;-1:-1:-1;10695:4:0;10719:17;10818:1;10807:12;;;;;:28;;;10823:7;:12;;10834:1;10823:12;10807:28;10803:859;;;10851:9;10863:5;:15;;;10879:6;10863:23;;;;;;;;;;;;;10851:35;;10923:2;10916:9;;:3;:9;;;:25;;;;;10929:7;:12;;10940:1;10929:12;10916:25;10915:58;;;;10954:2;10947:9;;:3;:9;;;;:25;;;;;10960:7;:12;;10971:1;10960:12;10947:25;10900:73;;10803:859;;;;11073:7;:12;;11084:1;11073:12;11069:593;;;11130:1;11122:3;11116:15;;;;11101:30;;11069:593;;;11222:7;:12;;11233:1;11222:12;11218:444;;;11278:1;11271:3;11265:14;;;11250:29;;11218:444;;;11387:7;:12;;11398:1;11387:12;11383:279;;;11467:4;11461:2;11452:11;;;11451:20;11490:8;11486:76;;11546:1;11539:3;11533:14;;;11518:29;;11486:76;11579:3;:8;;11586:1;11579:8;11575:77;;;11636:1;11628:3;11622:15;;;;11607:30;;11575:77;11383:279;;11730:8;;;;;11800:12;;;;11789:23;;;;;11944:162;;;;12031:1;12005:22;12008:5;12016:6;12008:14;12024:2;12005;:22::i;:::-;:27;;;;;;;11991:42;;12000:1;11991:42;11976:57;:12;;;:57;11944:162;;;12079:12;;;;;12094:1;12079:16;12064:31;;;;11944:162;12173:13;:11;:13::i;:::-;12166:20;10480:1713;-1:-1:-1;;;;;;;;10480:1713:0:o;27111:6520::-;27198:6;27232:10;27240:2;27232:10;;;;;;27279:11;;27383:4;27374:13;;27370:6215;;;27502:1;27492:6;:11;;;;:27;;;;;27516:3;27507:6;:12;;;27492:27;27488:532;;;27543:6;:11;;27553:1;27543:11;27539:431;;;-1:-1:-1;27565:4:0;27539:431;;;27613:6;:11;;27623:1;27613:11;27609:361;;;-1:-1:-1;27635:4:0;27609:361;;;27679:6;:13;;27689:3;27679:13;27675:295;;;-1:-1:-1;27703:4:0;27675:295;;;27744:6;:13;;27754:3;27744:13;27740:230;;;-1:-1:-1;27768:4:0;27740:230;;;27810:6;:13;;27820:3;27810:13;27806:164;;;-1:-1:-1;27834:4:0;27806:164;;;27875:6;:13;;27885:3;27875:13;27871:99;;;-1:-1:-1;27899:4:0;27871:99;;;27939:6;:13;;27949:3;27939:13;27935:35;;;-1:-1:-1;27963:4:0;27935:35;28004:1;27995:10;;27488:532;28073:11;;;28069:3190;;28133:4;28128:1;28120:9;;;28119:18;28166:4;28120:9;28159:11;;;28155:1203;;;28250:4;28242;:12;;;28238:1102;;28289:2;28282:9;;;;;;;28238:1102;28391:12;;;28387:953;;28438:11;;;;;;;;-1:-1:-1;28431:18:0;;-1:-1:-1;;28431:18:0;28387:953;28550:4;:12;;28558:4;28550:12;28546:794;;;28597:11;;;;;;;;-1:-1:-1;28590:18:0;;-1:-1:-1;;28590:18:0;28546:794;28712:4;:12;;28720:4;28712:12;28708:632;;;28759:27;28768:5;28762:11;;:2;:11;;;;28780:5;28775:2;:10;28759:2;:27::i;28708:632::-;28896:4;:12;;28904:4;28896:12;28892:448;;;-1:-1:-1;;;;28943:17:0;;;28955:4;28950:9;;28943:17;28936:24;;28892:448;29071:4;:12;;29079:4;29071:12;29067:273;;;-1:-1:-1;;;;29118:17:0;;;29130:4;29125:9;;29118:17;29111:24;;29067:273;29249:4;:12;;29257:4;29249:12;29245:95;;;29296:21;29305:2;29299:8;;:2;:8;;;;29314:2;29309;:7;29296:2;:21::i;29245:95::-;29502:4;:12;;29510:4;29502:12;:28;;;;29518:4;:12;;29526:4;29518:12;29502:28;29498:1025;;;29566:2;29561;:7;29554:14;;;;;;;29498:1025;29644:4;:12;;29652:4;29644:12;:28;;;;29660:4;:12;;29668:4;29660:12;29644:28;29640:883;;;29708:2;29703;:7;29696:14;;;;;;;29640:883;29778:4;:12;;29786:4;29778:12;29774:749;;;29826:2;29821;:7;29814:14;;;;;;;29774:749;29895:4;:12;;29903:4;29895:12;29891:632;;;29944:2;29939;:7;29931:16;;;;;;;29891:632;30015:4;:12;;30023:4;30015:12;30011:512;;;30064:2;30059;:7;30051:16;;;;;;;30011:512;30135:4;:12;;30143:4;30135:12;30131:392;;;-1:-1:-1;;;;30180:7:0;;;30178:10;30171:17;;30131:392;30279:4;:12;;30287:4;30279:12;30275:248;;;30338:2;30320:21;;30326:2;30320:21;;;:29;;30348:1;30320:29;;;30344:1;30320:29;30313:36;;;;;;;;;30275:248;30450:4;:12;;30458:4;30450:12;30446:77;;;30494:2;30491:5;;:2;:5;;;:13;;30503:1;30491:13;;30446:77;28069:3190;;;;30600:6;:13;;30610:3;30600:13;30596:663;;;30646:2;30640;:8;;;;30633:15;;;;;;30596:663;30709:6;:14;;30719:4;30709:14;30705:554;;;30770:4;:9;;30778:1;30770:9;30766:92;;;-1:-1:-1;;;30817:21:0;;;30803:36;;30766:92;30902:4;:12;;30910:4;30902:12;:28;;;;30918:4;:12;;30926:4;30918:12;30902:28;30898:347;;;30958:4;:12;;30966:4;30958:12;30954:75;;;31003:3;;;30954:75;31050:8;31084:113;31094:10;31091:13;;:18;31084:113;;31166:8;31137:3;31166:8;;;;;31137:3;31084:113;;;31225:1;-1:-1:-1;31218:8:0;;-1:-1:-1;;31218:8:0;30898:347;27370:6215;;;31296:4;31287:6;:13;;;31283:2302;;;31338:6;:14;;31348:4;31338:14;31334:1088;;;31379:42;31397:2;31402:1;31397:6;31407:1;31396:12;31391:2;:17;31383:26;;:3;:26;;;;31413:4;31382:35;31419:1;31379:2;:42::i;:::-;31372:49;;;;;;31334:1088;31476:6;:14;;31486:4;31476:14;31472:950;;;31517:45;31535:2;31540:1;31535:6;31545:1;31534:12;31529:2;:17;31521:26;;:3;:26;;;;31551:6;31520:37;31559:2;31517;:45::i;31472:950::-;31618:6;:14;;31628:4;31618:14;31614:808;;;-1:-1:-1;;;31665:21:0;31684:1;31679;31674:6;;31673:12;31665:21;;31718:36;;;31785:5;31780:10;;31665:21;;;;;31779:18;31772:25;;31614:808;31852:6;:14;;31862:4;31852:14;31848:574;;;31893:3;31886:10;;;;;;31848:574;31952:6;:14;;31962:4;31952:14;31948:474;;;32008:2;32013:1;32008:6;32018:1;32007:12;32002:2;:17;31994:26;;:3;:26;;;;32024:4;31993:35;31986:42;;;;;;31948:474;32084:6;:14;;32094:4;32084:14;32080:342;;;32140:2;32145:1;32140:6;32150:1;32139:12;32134:2;:17;32126:26;;:3;:26;;;;32156:6;32125:37;32118:44;;;;;;32080:342;32218:6;:14;;32228:4;32218:14;32214:208;;;-1:-1:-1;;;32265:26:0;32289:1;32284;32279:6;;32278:12;32273:2;:17;32265:26;;32323:41;;;32395:5;32390:10;;32265:26;;;;;32389:18;32382:25;;31283:2302;32464:6;:14;;32474:4;32464:14;32460:1125;;;-1:-1:-1;;;32513:4:0;32507:34;32539:1;32534;32529:6;;32528:12;32523:2;:17;32507:34;;32589:27;;;32569:48;;;32639:10;;32508:9;;;32507:34;;32638:18;32631:25;;32460:1125;32699:6;:14;;32709:4;32699:14;32695:890;;;-1:-1:-1;;;32748:6:0;32742:36;32776:1;32771;32766:6;;32765:12;32760:2;:17;32742:36;;32826:29;;;32806:50;;;32878:10;;32743:11;;;32742:36;;32877:18;32870:25;;32695:890;32939:6;:14;;32949:4;32939:14;32935:650;;;-1:-1:-1;;;32982:20:0;33000:1;32995;32990:6;;32989:12;32982:20;;33030:36;;;33094:5;33088:11;;32982:20;;;;;33087:19;33080:26;;32935:650;33149:6;:14;;33159:4;33149:14;33145:440;;;33186:2;33179:9;;;;;;33145:440;33232:6;:14;;33242:4;33232:14;33228:357;;;-1:-1:-1;;;33275:25:0;33298:1;33293;33288:6;;33287:12;33282:2;:17;33275:25;;33328:41;;;33397:5;33391:11;;33275:25;;;;;33390:19;33383:26;;33228:357;33452:6;:14;;33462:4;33452:14;33448:137;;;33489:3;33482:10;;;;;;33448:137;33535:6;:14;;33545:4;33535:14;33531:54;;;33572:2;33565:9;;;;;;33531:54;33595:29;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;15953:688;16039:12;16098:18;;:::i;:::-;-1:-1:-1;16158:4:0;16253:2;16241:14;;;;16233:41;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;16362:14;;;;;;;:30;;;16380:12;16362:30;16358:94;;;16437:4;16408:5;:15;;;16424:9;16408:26;;;;;;;;;:33;;;;:26;;;;;;:33;16358:94;16499:12;;;;;16488:23;;;;:8;;;:23;16551:1;16536:16;;;16521:31;;;16621:13;:11;:13::i;4429:5665::-;4472:7;4525:18;;:::i;:::-;-1:-1:-1;4629:15:0;;:18;;;;4585:4;4716:18;;;;4756;;;;4796;;;;;4585:4;;4609:17;;;;4716:18;4756;4829;;;4843:4;4829:18;4825:5090;;;4895:2;4918:4;4915:7;;:12;4911:112;;5003:4;5000:7;;4992:4;:16;4986:22;4911:112;5040:7;;;5036:141;;5072:10;;;;;5100:16;;;;;;;;5072:10;-1:-1:-1;5036:141:0;;;5160:2;5155:7;;5036:141;4825:5090;;;;5197:10;:18;;5211:4;5197:18;5193:4722;;;1690:10;5250:14;;5193:4722;;;5285:10;:18;;5299:4;5285:18;5281:4634;;;5361:1;5356:6;;5281:4634;;;5383:10;:18;;5397:4;5383:18;5379:4536;;;5458:4;5443:12;;;:19;5476:26;;;:14;;;:26;5523:13;:11;:13::i;:::-;5516:20;;;;;;;;;;;5379:4536;5557:10;:18;;5571:4;5557:18;5553:4362;;;5704:14;;;5700:2017;;;;;5809:22;;;1923:1;5809:22;5805:1912;;;5946:10;5959:27;5967:2;5972:10;5967:15;5984:1;5959:7;:27::i;:::-;6045:11;6076:6;;6096:17;;;;6115:20;;;;;6076:60;;;;;;;;;;;;;;;;;;;;5946:40;;-1:-1:-1;6045:11:0;;;;6076:6;;;;;:19;;:60;;;;;;;;;;;:6;:60;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6076:60:0;;;;;;;;;-1:-1:-1;6076:60:0;-1:-1:-1;6267:1:0;6259:10;;6357:1;6353:17;;;6428;;;6425:2;;;6458:5;6448:15;;6425:2;;6537:6;6533:2;6530:14;6527:2;;;6557;6547:12;;6527:2;6659:3;6654:1;6646:6;6642:14;6637:3;6633:24;6629:34;6622:41;;6755:3;6751:1;6739:9;6730:6;6727:1;6723:14;6719:30;6715:38;6711:48;6704:55;;6875:1;6871;6867;6855:9;6852:1;6848:17;6844:25;6840:33;6836:41;6998:1;6994;6990;6981:6;6969:9;6966:1;6962:17;6958:30;6954:38;6950:46;6946:54;6928:72;;7094:10;7090:15;7084:4;7080:26;7072:34;;7206:3;7198:4;7194:9;7189:3;7185:19;7182:28;7175:35;;;;7302:33;7311:2;7316:10;7311:15;7328:1;7331:3;7302:8;:33::i;:::-;7353:20;;;:38;;;;;;;;;-1:-1:-1;5805:1912:0;;-1:-1:-1;;5805:1912:0;;7453:18;;;1842:1;7453:18;7449:268;;;7618:2;7613:7;;7449:268;;;7664:10;7659:15;;1998:3;7692:10;;7449:268;5553:4362;;;7737:10;:18;;7751:4;7737:18;7733:2182;;;7888:15;;;1769:1;7888:15;;:34;;-1:-1:-1;7907:15:0;;;1804:1;7907:15;7888:34;:57;;;-1:-1:-1;7926:19:0;;;1881:1;7926:19;7888:57;7884:1340;;;7970:2;7965:7;;7884:1340;;;8040:23;;;1966:1;8040:23;8036:1188;;;8103:10;8116:27;8124:2;8129:10;8124:15;8141:1;8116:7;:27::i;:::-;8215:17;;;;8103:40;;-1:-1:-1;8363:1:0;8355:10;;8453:1;8449:17;8524:13;;;8521:2;;;8546:5;8540:11;;8521:2;8820:14;;;8634:1;8816:22;;;8812:32;;;;8713:26;8737:1;8626:10;;;8717:18;;;8713:26;8808:43;8622:20;;8912:12;8978:17;;;:23;9042:1;9019:20;;;:24;8630:2;-1:-1:-1;8630:2:0;8036:1188;;7733:2182;9244:10;:18;;9258:4;9244:18;9240:675;;;9330:2;:7;;9336:1;9330:7;9326:579;;;9399:14;;;;;:40;;-1:-1:-1;9417:22:0;;;1923:1;9417:22;9399:40;:62;;;-1:-1:-1;9443:18:0;;;1842:1;9443:18;9399:62;9395:376;;;9490:1;9485:6;;9395:376;;;9532:15;;;1769:1;9532:15;;:34;;-1:-1:-1;9551:15:0;;;1804:1;9551:15;9532:34;:61;;;-1:-1:-1;9570:23:0;;;1966:1;9570:23;9532:61;:84;;;-1:-1:-1;9597:19:0;;;1881:1;9597:19;9532:84;9528:243;;;9645:1;9640:6;;9528:243;;9326:579;9814:10;9809:15;;2032:4;9842:11;;9326:579;9925:15;;;;;:23;;;;:18;;;;:23;;;;9958:15;;:23;;;:18;;;;:23;-1:-1:-1;10003:12:0;;;;9992:23;;;:8;;;:23;10055:1;10040:16;10025:31;;;;;10074:13;:11;:13::i;:::-;10067:20;;;;;;;;;4429:5665;:::o;12534:2222::-;12628:12;12686:18;;:::i;:::-;-1:-1:-1;12746:4:0;12770:10;12879:4;12870:13;;;;12866:1545;;;-1:-1:-1;12905:8:0;;;;12866:1545;;;13012:5;:13;;13021:4;13012:13;13008:1403;;;13041:14;;;:8;;;:14;13008:1403;;;13159:5;:13;;13168:4;13159:13;13155:1256;;;-1:-1:-1;13194:8:0;;;;13155:1256;;;13301:5;:13;;13310:4;13301:13;13297:1114;;;13330:14;;;:8;;;:14;13297:1114;;;13459:5;:13;;13468:4;13459:13;13455:956;;;13578:9;13528:17;13508;;;13528;;;;13508:37;13585:2;13578:9;;;;;13560:8;;;:28;13602:22;:8;;;:22;13455:956;;;13749:5;:13;;13758:4;13749:13;13745:666;;;13812:11;13798;;;13812;;;13798:25;13863:2;13856:9;;;;;13838:8;;;:28;13880:22;:8;;;:22;13745:666;;;14041:5;:13;;14050:4;14041:13;14037:374;;;14107:3;14088:23;;14094:3;14088:23;;;;;;;;14070:42;;:8;;;:42;14144:23;;;;;;;;;;;;;;14126:42;;:8;;;:42;14037:374;;;14317:5;:13;;14326:4;14317:13;14313:98;;;14363:3;14357:9;;:3;:9;;;;;;;;14346:20;;;;:8;;;:20;14391:9;;;;;;;;;;;;14380:20;;:8;;;:20;14313:98;14496:14;;;;14492:77;;14555:3;14526:5;:15;;;14542:9;14526:26;;;;;;;;;:32;;;;:26;;;;;;:32;14492:77;14615:12;;;;;14604:23;;;;:8;;;:23;14667:1;14652:16;;;14637:31;;;14736:13;:11;:13::i;:::-;14729:20;12534:2222;-1:-1:-1;;;;;;;12534:2222:0:o;19636:1584::-;19784:14;19801:24;19813:11;19801;:24::i;:::-;19784:41;;19921:1;19914:5;19910:13;19907:2;;;19952:1;19949;19942:12;19907:2;20091;20273:15;;;20110:2;20099:14;;20087:10;20083:31;20080:1;20076:39;20233:16;;;20030:20;;20218:10;20207:22;;;20203:27;20193:38;20190:60;20679:5;20676:1;20672:13;20742:1;20727:375;20752:2;20749:1;20746:9;20727:375;;;20867:2;20855:15;;;20808:20;20898:12;;;20912:1;20894:20;20931:78;;;;21015:1;21010:78;;;;20887:201;;20931:78;20968:23;20983:7;20977:4;20968:23;:::i;:::-;20960:31;;20931:78;;21010;21047:23;21065:4;21056:7;21047:23;:::i;:::-;21039:31;;20887:201;-1:-1:-1;;20770:1:0;20763:9;20727:375;;;-1:-1:-1;;21193:4:0;21186:18;-1:-1:-1;;;;19845:1369:0:o;16845:500::-;17135:20;;;17159:7;17135:32;17128:3;:40;;;17217:14;;17256:17;;17250:24;;;17242:72;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;17324:14;16845:500;;;:::o;-1:-1:-1:-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;:::o;:::-;;;;;;;;;;;;;;;;;;;;;;;;:::o"
func init() { func init() {
if err := json.Unmarshal([]byte(MIPSStorageLayoutJSON), MIPSStorageLayout); err != nil { if err := json.Unmarshal([]byte(MIPSStorageLayoutJSON), MIPSStorageLayout); err != nil {
......
...@@ -30,8 +30,8 @@ var ( ...@@ -30,8 +30,8 @@ var (
// PreimageOracleMetaData contains all meta data concerning the PreimageOracle contract. // PreimageOracleMetaData contains all meta data concerning the PreimageOracle contract.
var PreimageOracleMetaData = &bind.MetaData{ var PreimageOracleMetaData = &bind.MetaData{
ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"partOffset\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"part\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"size\",\"type\":\"uint256\"}],\"name\":\"cheat\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"partOffset\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"preimage\",\"type\":\"bytes\"}],\"name\":\"loadKeccak256PreimagePart\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"preimageLengths\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"preimagePartOk\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"preimageParts\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"offset\",\"type\":\"uint256\"}],\"name\":\"readPreimage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"dat\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"datLen\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]", ABI: "[{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"partOffset\",\"type\":\"uint256\"},{\"internalType\":\"bytes32\",\"name\":\"key\",\"type\":\"bytes32\"},{\"internalType\":\"bytes32\",\"name\":\"part\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"size\",\"type\":\"uint256\"}],\"name\":\"cheat\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_preimage\",\"type\":\"bytes\"}],\"name\":\"computePreimageKey\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"key_\",\"type\":\"bytes32\"}],\"stateMutability\":\"pure\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"uint256\",\"name\":\"_partOffset\",\"type\":\"uint256\"},{\"internalType\":\"bytes\",\"name\":\"_preimage\",\"type\":\"bytes\"}],\"name\":\"loadKeccak256PreimagePart\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"name\":\"preimageLengths\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"preimagePartOk\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"\",\"type\":\"uint256\"}],\"name\":\"preimageParts\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"\",\"type\":\"bytes32\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes32\",\"name\":\"_key\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"_offset\",\"type\":\"uint256\"}],\"name\":\"readPreimage\",\"outputs\":[{\"internalType\":\"bytes32\",\"name\":\"dat_\",\"type\":\"bytes32\"},{\"internalType\":\"uint256\",\"name\":\"datLen_\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"}]",
Bin: "0x608060405234801561001057600080fd5b50610509806100206000396000f3fe608060405234801561001057600080fd5b50600436106100725760003560e01c8063e159261111610050578063e15926111461011b578063fe4ac08e14610130578063fef2b4ed146101a557600080fd5b806361238bde146100775780638542cf50146100b5578063e03110e1146100f3575b600080fd5b6100a26100853660046103b5565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6100e36100c33660046103b5565b600260209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016100ac565b6101066101013660046103b5565b6101c5565b604080519283526020830191909152016100ac565b61012e6101293660046103d7565b6102b6565b005b61012e61013e366004610453565b6000838152600260209081526040808320878452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558684528252808320968352958152858220939093559283529082905291902055565b6100a26101b3366004610485565b60006020819052908152604090205481565b6000828152600260209081526040808320848452909152812054819060ff1661024e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f707265696d616765206d75737420657869737400000000000000000000000000604482015260640160405180910390fd5b506000838152602081815260409091205461026a8160086104cd565b6102758560206104cd565b1061029357836102868260086104cd565b61029091906104e5565b91505b506000938452600160209081526040808620948652939052919092205492909150565b6044356000806008830186106102cb57600080fd5b60c083901b6080526088838682378087017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80151908490207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f02000000000000000000000000000000000000000000000000000000000000001760008181526002602090815260408083208b8452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915584845282528083209a83529981528982209390935590815290819052959095209190915550505050565b600080604083850312156103c857600080fd5b50508035926020909101359150565b6000806000604084860312156103ec57600080fd5b83359250602084013567ffffffffffffffff8082111561040b57600080fd5b818601915086601f83011261041f57600080fd5b81358181111561042e57600080fd5b87602082850101111561044057600080fd5b6020830194508093505050509250925092565b6000806000806080858703121561046957600080fd5b5050823594602084013594506040840135936060013592509050565b60006020828403121561049757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156104e0576104e061049e565b500190565b6000828210156104f7576104f761049e565b50039056fea164736f6c634300080f000a", Bin: "0x608060405234801561001057600080fd5b506105e2806100206000396000f3fe608060405234801561001057600080fd5b506004361061007d5760003560e01c8063e03110e11161005b578063e03110e114610111578063e159261114610139578063fe4ac08e1461014e578063fef2b4ed146101c357600080fd5b806361238bde146100825780638542cf50146100c0578063a57c202c146100fe575b600080fd5b6100ad610090366004610433565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6100ee6100ce366004610433565b600260209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016100b7565b6100ad61010c36600461049e565b6101e3565b61012461011f366004610433565b610242565b604080519283526020830191909152016100b7565b61014c6101473660046104e0565b610333565b005b61014c61015c36600461052c565b6000838152600260209081526040808320878452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558684528252808320968352958152858220939093559283529082905291902055565b6100ad6101d136600461055e565b60006020819052908152604090205481565b60243560c081901b608052600090608881858237207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0200000000000000000000000000000000000000000000000000000000000000179392505050565b6000828152600260209081526040808320848452909152812054819060ff166102cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f7072652d696d616765206d757374206578697374000000000000000000000000604482015260640160405180910390fd5b50600083815260208181526040909120546102e78160086105a6565b6102f28560206105a6565b1061031057836103038260086105a6565b61030d91906105be565b91505b506000938452600160209081526040808620948652939052919092205492909150565b6044356000806008830186111561034957600080fd5b60c083901b6080526088838682378087017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80151908490207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f02000000000000000000000000000000000000000000000000000000000000001760008181526002602090815260408083208b8452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915584845282528083209a83529981528982209390935590815290819052959095209190915550505050565b6000806040838503121561044657600080fd5b50508035926020909101359150565b60008083601f84011261046757600080fd5b50813567ffffffffffffffff81111561047f57600080fd5b60208301915083602082850101111561049757600080fd5b9250929050565b600080602083850312156104b157600080fd5b823567ffffffffffffffff8111156104c857600080fd5b6104d485828601610455565b90969095509350505050565b6000806000604084860312156104f557600080fd5b83359250602084013567ffffffffffffffff81111561051357600080fd5b61051f86828701610455565b9497909650939450505050565b6000806000806080858703121561054257600080fd5b5050823594602084013594506040840135936060013592509050565b60006020828403121561057057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156105b9576105b9610577565b500190565b6000828210156105d0576105d0610577565b50039056fea164736f6c634300080f000a",
} }
// PreimageOracleABI is the input ABI used to generate the binding from. // PreimageOracleABI is the input ABI used to generate the binding from.
...@@ -201,6 +201,37 @@ func (_PreimageOracle *PreimageOracleTransactorRaw) Transact(opts *bind.Transact ...@@ -201,6 +201,37 @@ func (_PreimageOracle *PreimageOracleTransactorRaw) Transact(opts *bind.Transact
return _PreimageOracle.Contract.contract.Transact(opts, method, params...) return _PreimageOracle.Contract.contract.Transact(opts, method, params...)
} }
// ComputePreimageKey is a free data retrieval call binding the contract method 0xa57c202c.
//
// Solidity: function computePreimageKey(bytes _preimage) pure returns(bytes32 key_)
func (_PreimageOracle *PreimageOracleCaller) ComputePreimageKey(opts *bind.CallOpts, _preimage []byte) ([32]byte, error) {
var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "computePreimageKey", _preimage)
if err != nil {
return *new([32]byte), err
}
out0 := *abi.ConvertType(out[0], new([32]byte)).(*[32]byte)
return out0, err
}
// ComputePreimageKey is a free data retrieval call binding the contract method 0xa57c202c.
//
// Solidity: function computePreimageKey(bytes _preimage) pure returns(bytes32 key_)
func (_PreimageOracle *PreimageOracleSession) ComputePreimageKey(_preimage []byte) ([32]byte, error) {
return _PreimageOracle.Contract.ComputePreimageKey(&_PreimageOracle.CallOpts, _preimage)
}
// ComputePreimageKey is a free data retrieval call binding the contract method 0xa57c202c.
//
// Solidity: function computePreimageKey(bytes _preimage) pure returns(bytes32 key_)
func (_PreimageOracle *PreimageOracleCallerSession) ComputePreimageKey(_preimage []byte) ([32]byte, error) {
return _PreimageOracle.Contract.ComputePreimageKey(&_PreimageOracle.CallOpts, _preimage)
}
// PreimageLengths is a free data retrieval call binding the contract method 0xfef2b4ed. // PreimageLengths is a free data retrieval call binding the contract method 0xfef2b4ed.
// //
// Solidity: function preimageLengths(bytes32 ) view returns(uint256) // Solidity: function preimageLengths(bytes32 ) view returns(uint256)
...@@ -296,13 +327,13 @@ func (_PreimageOracle *PreimageOracleCallerSession) PreimageParts(arg0 [32]byte, ...@@ -296,13 +327,13 @@ func (_PreimageOracle *PreimageOracleCallerSession) PreimageParts(arg0 [32]byte,
// ReadPreimage is a free data retrieval call binding the contract method 0xe03110e1. // ReadPreimage is a free data retrieval call binding the contract method 0xe03110e1.
// //
// Solidity: function readPreimage(bytes32 key, uint256 offset) view returns(bytes32 dat, uint256 datLen) // Solidity: function readPreimage(bytes32 _key, uint256 _offset) view returns(bytes32 dat_, uint256 datLen_)
func (_PreimageOracle *PreimageOracleCaller) ReadPreimage(opts *bind.CallOpts, key [32]byte, offset *big.Int) (struct { func (_PreimageOracle *PreimageOracleCaller) ReadPreimage(opts *bind.CallOpts, _key [32]byte, _offset *big.Int) (struct {
Dat [32]byte Dat [32]byte
DatLen *big.Int DatLen *big.Int
}, error) { }, error) {
var out []interface{} var out []interface{}
err := _PreimageOracle.contract.Call(opts, &out, "readPreimage", key, offset) err := _PreimageOracle.contract.Call(opts, &out, "readPreimage", _key, _offset)
outstruct := new(struct { outstruct := new(struct {
Dat [32]byte Dat [32]byte
...@@ -321,22 +352,22 @@ func (_PreimageOracle *PreimageOracleCaller) ReadPreimage(opts *bind.CallOpts, k ...@@ -321,22 +352,22 @@ func (_PreimageOracle *PreimageOracleCaller) ReadPreimage(opts *bind.CallOpts, k
// ReadPreimage is a free data retrieval call binding the contract method 0xe03110e1. // ReadPreimage is a free data retrieval call binding the contract method 0xe03110e1.
// //
// Solidity: function readPreimage(bytes32 key, uint256 offset) view returns(bytes32 dat, uint256 datLen) // Solidity: function readPreimage(bytes32 _key, uint256 _offset) view returns(bytes32 dat_, uint256 datLen_)
func (_PreimageOracle *PreimageOracleSession) ReadPreimage(key [32]byte, offset *big.Int) (struct { func (_PreimageOracle *PreimageOracleSession) ReadPreimage(_key [32]byte, _offset *big.Int) (struct {
Dat [32]byte Dat [32]byte
DatLen *big.Int DatLen *big.Int
}, error) { }, error) {
return _PreimageOracle.Contract.ReadPreimage(&_PreimageOracle.CallOpts, key, offset) return _PreimageOracle.Contract.ReadPreimage(&_PreimageOracle.CallOpts, _key, _offset)
} }
// ReadPreimage is a free data retrieval call binding the contract method 0xe03110e1. // ReadPreimage is a free data retrieval call binding the contract method 0xe03110e1.
// //
// Solidity: function readPreimage(bytes32 key, uint256 offset) view returns(bytes32 dat, uint256 datLen) // Solidity: function readPreimage(bytes32 _key, uint256 _offset) view returns(bytes32 dat_, uint256 datLen_)
func (_PreimageOracle *PreimageOracleCallerSession) ReadPreimage(key [32]byte, offset *big.Int) (struct { func (_PreimageOracle *PreimageOracleCallerSession) ReadPreimage(_key [32]byte, _offset *big.Int) (struct {
Dat [32]byte Dat [32]byte
DatLen *big.Int DatLen *big.Int
}, error) { }, error) {
return _PreimageOracle.Contract.ReadPreimage(&_PreimageOracle.CallOpts, key, offset) return _PreimageOracle.Contract.ReadPreimage(&_PreimageOracle.CallOpts, _key, _offset)
} }
// Cheat is a paid mutator transaction binding the contract method 0xfe4ac08e. // Cheat is a paid mutator transaction binding the contract method 0xfe4ac08e.
...@@ -362,21 +393,21 @@ func (_PreimageOracle *PreimageOracleTransactorSession) Cheat(partOffset *big.In ...@@ -362,21 +393,21 @@ func (_PreimageOracle *PreimageOracleTransactorSession) Cheat(partOffset *big.In
// LoadKeccak256PreimagePart is a paid mutator transaction binding the contract method 0xe1592611. // LoadKeccak256PreimagePart is a paid mutator transaction binding the contract method 0xe1592611.
// //
// Solidity: function loadKeccak256PreimagePart(uint256 partOffset, bytes preimage) returns() // Solidity: function loadKeccak256PreimagePart(uint256 _partOffset, bytes _preimage) returns()
func (_PreimageOracle *PreimageOracleTransactor) LoadKeccak256PreimagePart(opts *bind.TransactOpts, partOffset *big.Int, preimage []byte) (*types.Transaction, error) { func (_PreimageOracle *PreimageOracleTransactor) LoadKeccak256PreimagePart(opts *bind.TransactOpts, _partOffset *big.Int, _preimage []byte) (*types.Transaction, error) {
return _PreimageOracle.contract.Transact(opts, "loadKeccak256PreimagePart", partOffset, preimage) return _PreimageOracle.contract.Transact(opts, "loadKeccak256PreimagePart", _partOffset, _preimage)
} }
// LoadKeccak256PreimagePart is a paid mutator transaction binding the contract method 0xe1592611. // LoadKeccak256PreimagePart is a paid mutator transaction binding the contract method 0xe1592611.
// //
// Solidity: function loadKeccak256PreimagePart(uint256 partOffset, bytes preimage) returns() // Solidity: function loadKeccak256PreimagePart(uint256 _partOffset, bytes _preimage) returns()
func (_PreimageOracle *PreimageOracleSession) LoadKeccak256PreimagePart(partOffset *big.Int, preimage []byte) (*types.Transaction, error) { func (_PreimageOracle *PreimageOracleSession) LoadKeccak256PreimagePart(_partOffset *big.Int, _preimage []byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadKeccak256PreimagePart(&_PreimageOracle.TransactOpts, partOffset, preimage) return _PreimageOracle.Contract.LoadKeccak256PreimagePart(&_PreimageOracle.TransactOpts, _partOffset, _preimage)
} }
// LoadKeccak256PreimagePart is a paid mutator transaction binding the contract method 0xe1592611. // LoadKeccak256PreimagePart is a paid mutator transaction binding the contract method 0xe1592611.
// //
// Solidity: function loadKeccak256PreimagePart(uint256 partOffset, bytes preimage) returns() // Solidity: function loadKeccak256PreimagePart(uint256 _partOffset, bytes _preimage) returns()
func (_PreimageOracle *PreimageOracleTransactorSession) LoadKeccak256PreimagePart(partOffset *big.Int, preimage []byte) (*types.Transaction, error) { func (_PreimageOracle *PreimageOracleTransactorSession) LoadKeccak256PreimagePart(_partOffset *big.Int, _preimage []byte) (*types.Transaction, error) {
return _PreimageOracle.Contract.LoadKeccak256PreimagePart(&_PreimageOracle.TransactOpts, partOffset, preimage) return _PreimageOracle.Contract.LoadKeccak256PreimagePart(&_PreimageOracle.TransactOpts, _partOffset, _preimage)
} }
...@@ -13,9 +13,9 @@ const PreimageOracleStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contrac ...@@ -13,9 +13,9 @@ const PreimageOracleStorageLayoutJSON = "{\"storage\":[{\"astId\":1000,\"contrac
var PreimageOracleStorageLayout = new(solc.StorageLayout) var PreimageOracleStorageLayout = new(solc.StorageLayout)
var PreimageOracleDeployedBin = "0x608060405234801561001057600080fd5b50600436106100725760003560e01c8063e159261111610050578063e15926111461011b578063fe4ac08e14610130578063fef2b4ed146101a557600080fd5b806361238bde146100775780638542cf50146100b5578063e03110e1146100f3575b600080fd5b6100a26100853660046103b5565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6100e36100c33660046103b5565b600260209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016100ac565b6101066101013660046103b5565b6101c5565b604080519283526020830191909152016100ac565b61012e6101293660046103d7565b6102b6565b005b61012e61013e366004610453565b6000838152600260209081526040808320878452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558684528252808320968352958152858220939093559283529082905291902055565b6100a26101b3366004610485565b60006020819052908152604090205481565b6000828152600260209081526040808320848452909152812054819060ff1661024e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f707265696d616765206d75737420657869737400000000000000000000000000604482015260640160405180910390fd5b506000838152602081815260409091205461026a8160086104cd565b6102758560206104cd565b1061029357836102868260086104cd565b61029091906104e5565b91505b506000938452600160209081526040808620948652939052919092205492909150565b6044356000806008830186106102cb57600080fd5b60c083901b6080526088838682378087017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80151908490207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f02000000000000000000000000000000000000000000000000000000000000001760008181526002602090815260408083208b8452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915584845282528083209a83529981528982209390935590815290819052959095209190915550505050565b600080604083850312156103c857600080fd5b50508035926020909101359150565b6000806000604084860312156103ec57600080fd5b83359250602084013567ffffffffffffffff8082111561040b57600080fd5b818601915086601f83011261041f57600080fd5b81358181111561042e57600080fd5b87602082850101111561044057600080fd5b6020830194508093505050509250925092565b6000806000806080858703121561046957600080fd5b5050823594602084013594506040840135936060013592509050565b60006020828403121561049757600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156104e0576104e061049e565b500190565b6000828210156104f7576104f761049e565b50039056fea164736f6c634300080f000a" var PreimageOracleDeployedBin = "0x608060405234801561001057600080fd5b506004361061007d5760003560e01c8063e03110e11161005b578063e03110e114610111578063e159261114610139578063fe4ac08e1461014e578063fef2b4ed146101c357600080fd5b806361238bde146100825780638542cf50146100c0578063a57c202c146100fe575b600080fd5b6100ad610090366004610433565b600160209081526000928352604080842090915290825290205481565b6040519081526020015b60405180910390f35b6100ee6100ce366004610433565b600260209081526000928352604080842090915290825290205460ff1681565b60405190151581526020016100b7565b6100ad61010c36600461049e565b6101e3565b61012461011f366004610433565b610242565b604080519283526020830191909152016100b7565b61014c6101473660046104e0565b610333565b005b61014c61015c36600461052c565b6000838152600260209081526040808320878452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001660019081179091558684528252808320968352958152858220939093559283529082905291902055565b6100ad6101d136600461055e565b60006020819052908152604090205481565b60243560c081901b608052600090608881858237207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f0200000000000000000000000000000000000000000000000000000000000000179392505050565b6000828152600260209081526040808320848452909152812054819060ff166102cb576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601460248201527f7072652d696d616765206d757374206578697374000000000000000000000000604482015260640160405180910390fd5b50600083815260208181526040909120546102e78160086105a6565b6102f28560206105a6565b1061031057836103038260086105a6565b61030d91906105be565b91505b506000938452600160209081526040808620948652939052919092205492909150565b6044356000806008830186111561034957600080fd5b60c083901b6080526088838682378087017ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff80151908490207effffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff167f02000000000000000000000000000000000000000000000000000000000000001760008181526002602090815260408083208b8452825280832080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016600190811790915584845282528083209a83529981528982209390935590815290819052959095209190915550505050565b6000806040838503121561044657600080fd5b50508035926020909101359150565b60008083601f84011261046757600080fd5b50813567ffffffffffffffff81111561047f57600080fd5b60208301915083602082850101111561049757600080fd5b9250929050565b600080602083850312156104b157600080fd5b823567ffffffffffffffff8111156104c857600080fd5b6104d485828601610455565b90969095509350505050565b6000806000604084860312156104f557600080fd5b83359250602084013567ffffffffffffffff81111561051357600080fd5b61051f86828701610455565b9497909650939450505050565b6000806000806080858703121561054257600080fd5b5050823594602084013594506040840135936060013592509050565b60006020828403121561057057600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082198211156105b9576105b9610577565b500190565b6000828210156105d0576105d0610577565b50039056fea164736f6c634300080f000a"
var PreimageOracleDeployedSourceMap = "57:2945:58:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;143:68;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;413:25:228;;;401:2;386:18;143:68:58;;;;;;;;217:66;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;614:14:228;;607:22;589:41;;577:2;562:18;217:66:58;449:187:228;290:454:58;;;;;;:::i;:::-;;:::i;:::-;;;;815:25:228;;;871:2;856:18;;849:34;;;;788:18;290:454:58;641:248:228;1537:1463:58;;;;;;:::i;:::-;;:::i;:::-;;1086:262;;;;;;:::i;:::-;1219:19;;;;:14;:19;;;;;;;;:31;;;;;;;;:38;;;;1253:4;1219:38;;;;;;1267:18;;;;;;;;:30;;;;;;;;;:37;;;;1314:20;;;;;;;;;;:27;1086:262;87:50;;;;;;:::i;:::-;;;;;;;;;;;;;;;290:454;388:11;439:19;;;:14;:19;;;;;;;;:27;;;;;;;;;388:11;;439:27;;431:59;;;;;;;2517:2:228;431:59:58;;;2499:21:228;2556:2;2536:18;;;2529:30;2595:21;2575:18;;;2568:49;2634:18;;431:59:58;;;;;;;;-1:-1:-1;521:14:58;538:20;;;509:2;538:20;;;;;;;;631:10;538:20;640:1;631:10;:::i;:::-;616:11;:6;625:2;616:11;:::i;:::-;:25;612:84;;679:6;666:10;:6;675:1;666:10;:::i;:::-;:19;;;;:::i;:::-;657:28;;612:84;-1:-1:-1;711:18:58;;;;:13;:18;;;;;;;;:26;;;;;;;;;;;;290:454;;-1:-1:-1;290:454:58:o;1537:1463::-;1831:4;1818:18;1636:12;;1966:1;1956:12;;1941:28;;1931:84;;1999:1;1996;1989:12;1931:84;2258:3;2254:14;;;2158:4;2242:27;2289:11;2263:4;2408:15;2289:11;2390:40;2620:28;;;2624:11;2620:28;2614:35;2671:20;;;;2818:19;2811:27;2840:11;2808:44;2871:19;;;;2849:1;2871:19;;;;;;;;:31;;;;;;;;:38;;;;2905:4;2871:38;;;;;;2919:18;;;;;;;;:30;;;;;;;;;:37;;;;2966:20;;;;;;;;;;;:27;;;;-1:-1:-1;;;;1537:1463:58:o;14:248:228:-;82:6;90;143:2;131:9;122:7;118:23;114:32;111:52;;;159:1;156;149:12;111:52;-1:-1:-1;;182:23:228;;;252:2;237:18;;;224:32;;-1:-1:-1;14:248:228:o;894:659::-;973:6;981;989;1042:2;1030:9;1021:7;1017:23;1013:32;1010:52;;;1058:1;1055;1048:12;1010:52;1094:9;1081:23;1071:33;;1155:2;1144:9;1140:18;1127:32;1178:18;1219:2;1211:6;1208:14;1205:34;;;1235:1;1232;1225:12;1205:34;1273:6;1262:9;1258:22;1248:32;;1318:7;1311:4;1307:2;1303:13;1299:27;1289:55;;1340:1;1337;1330:12;1289:55;1380:2;1367:16;1406:2;1398:6;1395:14;1392:34;;;1422:1;1419;1412:12;1392:34;1467:7;1462:2;1453:6;1449:2;1445:15;1441:24;1438:37;1435:57;;;1488:1;1485;1478:12;1435:57;1519:2;1515;1511:11;1501:21;;1541:6;1531:16;;;;;894:659;;;;;:::o;1558:385::-;1644:6;1652;1660;1668;1721:3;1709:9;1700:7;1696:23;1692:33;1689:53;;;1738:1;1735;1728:12;1689:53;-1:-1:-1;;1761:23:228;;;1831:2;1816:18;;1803:32;;-1:-1:-1;1882:2:228;1867:18;;1854:32;;1933:2;1918:18;1905:32;;-1:-1:-1;1558:385:228;-1:-1:-1;1558:385:228:o;1948:180::-;2007:6;2060:2;2048:9;2039:7;2035:23;2031:32;2028:52;;;2076:1;2073;2066:12;2028:52;-1:-1:-1;2099:23:228;;1948:180;-1:-1:-1;1948:180:228:o;2663:184::-;2715:77;2712:1;2705:88;2812:4;2809:1;2802:15;2836:4;2833:1;2826:15;2852:128;2892:3;2923:1;2919:6;2916:1;2913:13;2910:39;;;2929:18;;:::i;:::-;-1:-1:-1;2965:9:228;;2852:128::o;2985:125::-;3025:4;3053:1;3050;3047:8;3044:34;;;3058:18;;:::i;:::-;-1:-1:-1;3095:9:228;;2985:125::o" var PreimageOracleDeployedSourceMap = "144:4615:67:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;357:68;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;413:25:283;;;401:2;386:18;357:68:67;;;;;;;;501:66;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;614:14:283;;607:22;589:41;;577:2;562:18;501:66:67;449:187:283;2154:850:67;;;;;;:::i;:::-;;:::i;838:564::-;;;;;;:::i;:::-;;:::i;:::-;;;;1581:25:283;;;1637:2;1622:18;;1615:34;;;;1554:18;838:564:67;1407:248:283;3295:1462:67;;;;;;:::i;:::-;;:::i;:::-;;1744:262;;;;;;:::i;:::-;1877:19;;;;:14;:19;;;;;;;;:31;;;;;;;;:38;;;;1911:4;1877:38;;;;;;1925:18;;;;;;;;:30;;;;;;;;;:37;;;;1972:20;;;;;;;;;;:27;1744:262;238:50;;;;;;:::i;:::-;;;;;;;;;;;;;;;2154:850;2321:4;2308:18;2567:3;2563:14;;;2458:4;2551:27;2231:12;;2598:11;2308:18;2718:16;2598:11;2700:41;2840:20;2954:19;2947:27;2976:11;2944:44;;2154:850;-1:-1:-1;;;2154:850:67:o;838:564::-;938:12;991:20;;;:14;:20;;;;;;;;:29;;;;;;;;;938:12;;991:29;;983:62;;;;;;;3101:2:283;983:62:67;;;3083:21:283;3140:2;3120:18;;;3113:30;3179:22;3159:18;;;3152:50;3219:18;;983:62:67;;;;;;;;-1:-1:-1;1176:14:67;1193:21;;;1164:2;1193:21;;;;;;;;1244:10;1193:21;1253:1;1244:10;:::i;:::-;1228:12;:7;1238:2;1228:12;:::i;:::-;:26;1224:87;;1293:7;1280:10;:6;1289:1;1280:10;:::i;:::-;:20;;;;:::i;:::-;1270:30;;1224:87;-1:-1:-1;1367:19:67;;;;:13;:19;;;;;;;;:28;;;;;;;;;;;;838:564;;-1:-1:-1;838:564:67:o;3295:1462::-;3591:4;3578:18;3396:12;;3720:1;3710:12;;3694:29;;3691:77;;;3752:1;3749;3742:12;3691:77;4011:3;4007:14;;;3911:4;3995:27;4042:11;4016:4;4161:16;4042:11;4143:41;4374:29;;;4378:11;4374:29;4368:36;4426:20;;;;4573:19;4566:27;4595:11;4563:44;4626:19;;;;4604:1;4626:19;;;;;;;;:32;;;;;;;;:39;;;;4661:4;4626:39;;;;;;4675:18;;;;;;;;:31;;;;;;;;;:38;;;;4723:20;;;;;;;;;;;:27;;;;-1:-1:-1;;;;3295:1462:67:o;14:248:283:-;82:6;90;143:2;131:9;122:7;118:23;114:32;111:52;;;159:1;156;149:12;111:52;-1:-1:-1;;182:23:283;;;252:2;237:18;;;224:32;;-1:-1:-1;14:248:283:o;641:347::-;692:8;702:6;756:3;749:4;741:6;737:17;733:27;723:55;;774:1;771;764:12;723:55;-1:-1:-1;797:20:283;;840:18;829:30;;826:50;;;872:1;869;862:12;826:50;909:4;901:6;897:17;885:29;;961:3;954:4;945:6;937;933:19;929:30;926:39;923:59;;;978:1;975;968:12;923:59;641:347;;;;;:::o;993:409::-;1063:6;1071;1124:2;1112:9;1103:7;1099:23;1095:32;1092:52;;;1140:1;1137;1130:12;1092:52;1180:9;1167:23;1213:18;1205:6;1202:30;1199:50;;;1245:1;1242;1235:12;1199:50;1284:58;1334:7;1325:6;1314:9;1310:22;1284:58;:::i;:::-;1361:8;;1258:84;;-1:-1:-1;993:409:283;-1:-1:-1;;;;993:409:283:o;1660:477::-;1739:6;1747;1755;1808:2;1796:9;1787:7;1783:23;1779:32;1776:52;;;1824:1;1821;1814:12;1776:52;1860:9;1847:23;1837:33;;1921:2;1910:9;1906:18;1893:32;1948:18;1940:6;1937:30;1934:50;;;1980:1;1977;1970:12;1934:50;2019:58;2069:7;2060:6;2049:9;2045:22;2019:58;:::i;:::-;1660:477;;2096:8;;-1:-1:-1;1993:84:283;;-1:-1:-1;;;;1660:477:283:o;2142:385::-;2228:6;2236;2244;2252;2305:3;2293:9;2284:7;2280:23;2276:33;2273:53;;;2322:1;2319;2312:12;2273:53;-1:-1:-1;;2345:23:283;;;2415:2;2400:18;;2387:32;;-1:-1:-1;2466:2:283;2451:18;;2438:32;;2517:2;2502:18;2489:32;;-1:-1:-1;2142:385:283;-1:-1:-1;2142:385:283:o;2532:180::-;2591:6;2644:2;2632:9;2623:7;2619:23;2615:32;2612:52;;;2660:1;2657;2650:12;2612:52;-1:-1:-1;2683:23:283;;2532:180;-1:-1:-1;2532:180:283:o;3248:184::-;3300:77;3297:1;3290:88;3397:4;3394:1;3387:15;3421:4;3418:1;3411:15;3437:128;3477:3;3508:1;3504:6;3501:1;3498:13;3495:39;;;3514:18;;:::i;:::-;-1:-1:-1;3550:9:283;;3437:128::o;3570:125::-;3610:4;3638:1;3635;3632:8;3629:34;;;3643:18;;:::i;:::-;-1:-1:-1;3680:9:283;;3570:125::o"
func init() { func init() {
if err := json.Unmarshal([]byte(PreimageOracleStorageLayoutJSON), PreimageOracleStorageLayout); err != nil { if err := json.Unmarshal([]byte(PreimageOracleStorageLayoutJSON), PreimageOracleStorageLayout); err != nil {
......
...@@ -22,6 +22,7 @@ type flags struct { ...@@ -22,6 +22,7 @@ type flags struct {
SourceMaps string SourceMaps string
OutDir string OutDir string
Package string Package string
MonorepoBase string
} }
type data struct { type data struct {
...@@ -39,8 +40,14 @@ func main() { ...@@ -39,8 +40,14 @@ func main() {
flag.StringVar(&f.Contracts, "contracts", "artifacts.json", "Path to file containing list of contracts to generate bindings for") flag.StringVar(&f.Contracts, "contracts", "artifacts.json", "Path to file containing list of contracts to generate bindings for")
flag.StringVar(&f.SourceMaps, "source-maps", "", "Comma-separated list of contracts to generate source-maps for") flag.StringVar(&f.SourceMaps, "source-maps", "", "Comma-separated list of contracts to generate source-maps for")
flag.StringVar(&f.Package, "package", "artifacts", "Go package name") flag.StringVar(&f.Package, "package", "artifacts", "Go package name")
flag.StringVar(&f.MonorepoBase, "monorepo-base", "", "Base of the monorepo")
flag.Parse() flag.Parse()
if f.MonorepoBase == "" {
log.Fatal("must provide -monorepo-base")
}
log.Printf("Using monorepo base %s\n", f.MonorepoBase)
contractData, err := os.ReadFile(f.Contracts) contractData, err := os.ReadFile(f.Contracts)
if err != nil { if err != nil {
log.Fatal("error reading contract list: %w\n", err) log.Fatal("error reading contract list: %w\n", err)
...@@ -72,21 +79,47 @@ func main() { ...@@ -72,21 +79,47 @@ func main() {
defer os.RemoveAll(dir) defer os.RemoveAll(dir)
log.Printf("created temp dir %s\n", dir) log.Printf("created temp dir %s\n", dir)
// If some contracts have the same name then the path to their
// artifact depends on their full import path. Scan over all artifacts
// and hold a mapping from the contract name to the contract path.
// Walk walks the directory deterministically, so the later instance
// of the contract with the same name will be used
artifactPaths := make(map[string]string)
if err := filepath.Walk(f.ForgeArtifacts,
func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
base := filepath.Base(path)
if strings.HasSuffix(base, ".json") {
name := base[:len(base)-5]
if _, ok := artifactPaths[name]; !ok {
artifactPaths[name] = path
}
}
return nil
}); err != nil {
log.Fatal(err)
}
for _, name := range contracts { for _, name := range contracts {
log.Printf("generating code for %s\n", name) log.Printf("generating code for %s\n", name)
forgeArtifactData, err := os.ReadFile(path.Join(f.ForgeArtifacts, name+".sol", name+".json")) artifactPath := path.Join(f.ForgeArtifacts, name+".sol", name+".json")
forgeArtifactData, err := os.ReadFile(artifactPath)
if errors.Is(err, os.ErrNotExist) { if errors.Is(err, os.ErrNotExist) {
log.Fatalf("cannot find forge-artifact of %q\n", name) artifactPath = artifactPaths[name]
forgeArtifactData, err = os.ReadFile(artifactPath)
if errors.Is(err, os.ErrNotExist) {
log.Fatalf("cannot find forge-artifact of %q\n", name)
}
} }
log.Printf("using forge-artifact %s\n", artifactPath)
var artifact foundry.Artifact var artifact foundry.Artifact
if err := json.Unmarshal(forgeArtifactData, &artifact); err != nil { if err := json.Unmarshal(forgeArtifactData, &artifact); err != nil {
log.Fatalf("failed to parse forge artifact of %q: %v\n", name, err) log.Fatalf("failed to parse forge artifact of %q: %v\n", name, err)
} }
if err != nil {
log.Fatalf("error reading storage layout %s: %v\n", name, err)
}
rawAbi := artifact.Abi rawAbi := artifact.Abi
if err != nil { if err != nil {
...@@ -121,7 +154,7 @@ func main() { ...@@ -121,7 +154,7 @@ func main() {
} }
storage := artifact.StorageLayout storage := artifact.StorageLayout
canonicalStorage := ast.CanonicalizeASTIDs(&storage) canonicalStorage := ast.CanonicalizeASTIDs(&storage, f.MonorepoBase)
ser, err := json.Marshal(canonicalStorage) ser, err := json.Marshal(canonicalStorage)
if err != nil { if err != nil {
log.Fatalf("error marshaling storage: %v\n", err) log.Fatalf("error marshaling storage: %v\n", err)
......
package op_challenger package op_challenger
import ( import (
"fmt"
"time"
"github.com/ethereum-optimism/optimism/op-bindings/bindings"
"github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-challenger/config"
"github.com/ethereum-optimism/optimism/op-challenger/fault"
"github.com/ethereum-optimism/optimism/op-service/txmgr"
"github.com/ethereum-optimism/optimism/op-service/txmgr/metrics"
"github.com/ethereum/go-ethereum/ethclient"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
// Main is the programmatic entry-point for running op-challenger // Main is the programmatic entry-point for running op-challenger
func Main(logger log.Logger, cfg *config.Config) error { func Main(logger log.Logger, cfg *config.Config) error {
client, err := ethclient.Dial(cfg.L1EthRpc)
if err != nil {
return fmt.Errorf("failed to dial L1: %w", err)
}
txMgr, err := txmgr.NewSimpleTxManager("challenger", logger, &metrics.NoopTxMetrics{}, cfg.TxMgrConfig)
if err != nil {
return fmt.Errorf("failed to create the transaction manager: %w", err)
}
contract, err := bindings.NewFaultDisputeGameCaller(cfg.GameAddress, client)
if err != nil {
return fmt.Errorf("failed to bind the fault dispute game contract: %w", err)
}
loader := fault.NewLoader(logger, contract)
responder, err := fault.NewFaultResponder(logger, txMgr, cfg.GameAddress)
if err != nil {
return fmt.Errorf("failed to create the responder: %w", err)
}
gameDepth := 4
trace := fault.NewAlphabetProvider(cfg.AlphabetTrace, uint64(gameDepth))
agent := fault.NewAgent(loader, gameDepth, trace, responder, cfg.AgreeWithProposedOutput, logger)
logger.Info("Fault game started") logger.Info("Fault game started")
return nil
for {
logger.Info("Performing action")
_ = agent.Act()
time.Sleep(300 * time.Millisecond)
}
} }
#!/bin/bash
set -euo pipefail
DIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)
cd "$DIR"
DISPUTE_GAME_PROXY="0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e"
CHARLIE_ADDRESS="0xF45B7537828CB2fffBC69996B054c2Aaf36DC778"
CHARLIE_KEY="74feb147d72bfae943e6b4e483410933d9e447d5dc47d52432dcc2c1454dabb7"
MALLORY_ADDRESS="0x4641c704a6c743f73ee1f36C7568Fbf4b80681e4"
MALLORY_KEY="28d7045146193f5f4eeb151c4843544b1b0d30a7ac1680c845a416fac65a7715"
FAULT_GAME_ADDRESS="0x8daf17a20c9dba35f005b6324f493785d239719d"
./bin/op-challenger --l1-eth-rpc http://localhost:8545 --alphabet "abcdefgh" --game-address $FAULT_GAME_ADDRESS --private-key $CHARLIE_KEY --num-confirmations 1 --agree-with-proposed-output=true
package main package main
import ( import (
"fmt"
"testing" "testing"
"github.com/ethereum-optimism/optimism/op-challenger/config" "github.com/ethereum-optimism/optimism/op-challenger/config"
...@@ -11,9 +12,10 @@ import ( ...@@ -11,9 +12,10 @@ import (
) )
var ( var (
l1EthRpc = "http://example.com:8545" l1EthRpc = "http://example.com:8545"
gameAddressValue = "0xaa00000000000000000000000000000000000000" gameAddressValue = "0xaa00000000000000000000000000000000000000"
alphabetTrace = "abcdefghijz" alphabetTrace = "abcdefghijz"
agreeWithProposedOutput = "true"
) )
func TestLogLevel(t *testing.T) { func TestLogLevel(t *testing.T) {
...@@ -33,12 +35,12 @@ func TestLogLevel(t *testing.T) { ...@@ -33,12 +35,12 @@ func TestLogLevel(t *testing.T) {
func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) { func TestDefaultCLIOptionsMatchDefaultConfig(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs()) cfg := configForArgs(t, addRequiredArgs())
defaultCfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), alphabetTrace) defaultCfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), alphabetTrace, true)
require.Equal(t, defaultCfg, cfg) require.Equal(t, defaultCfg, cfg)
} }
func TestDefaultConfigIsValid(t *testing.T) { func TestDefaultConfigIsValid(t *testing.T) {
cfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), alphabetTrace) cfg := config.NewConfig(l1EthRpc, common.HexToAddress(gameAddressValue), alphabetTrace, true)
require.NoError(t, cfg.Check()) require.NoError(t, cfg.Check())
} }
...@@ -89,6 +91,24 @@ func TestTxManagerFlagsSupported(t *testing.T) { ...@@ -89,6 +91,24 @@ func TestTxManagerFlagsSupported(t *testing.T) {
require.Equal(t, uint64(7), cfg.TxMgrConfig.NumConfirmations) require.Equal(t, uint64(7), cfg.TxMgrConfig.NumConfirmations)
} }
func TestAgreeWithProposedOutput(t *testing.T) {
t.Run("MustBeProvided", func(t *testing.T) {
verifyArgsInvalid(t, "flag agree-with-proposed-output is required", addRequiredArgsExcept("--agree-with-proposed-output"))
})
t.Run("Enabled", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs("--agree-with-proposed-output"))
require.True(t, cfg.AgreeWithProposedOutput)
})
t.Run("EnabledWithArg", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs("--agree-with-proposed-output=true"))
require.True(t, cfg.AgreeWithProposedOutput)
})
t.Run("Disabled", func(t *testing.T) {
cfg := configForArgs(t, addRequiredArgs("--agree-with-proposed-output=false"))
require.False(t, cfg.AgreeWithProposedOutput)
})
}
func verifyArgsInvalid(t *testing.T, messageContains string, cliArgs []string) { func verifyArgsInvalid(t *testing.T, messageContains string, cliArgs []string) {
_, _, err := runWithArgs(cliArgs) _, _, err := runWithArgs(cliArgs)
require.ErrorContains(t, err, messageContains) require.ErrorContains(t, err, messageContains)
...@@ -103,7 +123,7 @@ func configForArgs(t *testing.T, cliArgs []string) config.Config { ...@@ -103,7 +123,7 @@ func configForArgs(t *testing.T, cliArgs []string) config.Config {
func runWithArgs(cliArgs []string) (log.Logger, config.Config, error) { func runWithArgs(cliArgs []string) (log.Logger, config.Config, error) {
cfg := new(config.Config) cfg := new(config.Config)
var logger log.Logger var logger log.Logger
fullArgs := append([]string{"op-program"}, cliArgs...) fullArgs := append([]string{"op-challenger"}, cliArgs...)
err := run(fullArgs, func(log log.Logger, config *config.Config) error { err := run(fullArgs, func(log log.Logger, config *config.Config) error {
logger = log logger = log
cfg = config cfg = config
...@@ -126,17 +146,17 @@ func addRequiredArgsExcept(name string, optionalArgs ...string) []string { ...@@ -126,17 +146,17 @@ func addRequiredArgsExcept(name string, optionalArgs ...string) []string {
func requiredArgs() map[string]string { func requiredArgs() map[string]string {
return map[string]string{ return map[string]string{
"--l1-eth-rpc": l1EthRpc, "--agree-with-proposed-output": agreeWithProposedOutput,
"--game-address": gameAddressValue, "--l1-eth-rpc": l1EthRpc,
"--alphabet": alphabetTrace, "--game-address": gameAddressValue,
"--alphabet": alphabetTrace,
} }
} }
func toArgList(req map[string]string) []string { func toArgList(req map[string]string) []string {
var combined []string var combined []string
for name, value := range req { for name, value := range req {
combined = append(combined, name) combined = append(combined, fmt.Sprintf("%s=%s", name, value))
combined = append(combined, value)
} }
return combined return combined
} }
...@@ -21,22 +21,26 @@ var ( ...@@ -21,22 +21,26 @@ var (
// This also contains config options for auxiliary services. // This also contains config options for auxiliary services.
// It is used to initialize the challenger. // It is used to initialize the challenger.
type Config struct { type Config struct {
L1EthRpc string // L1 RPC Url L1EthRpc string // L1 RPC Url
GameAddress common.Address // Address of the fault game GameAddress common.Address // Address of the fault game
AlphabetTrace string // String for the AlphabetTraceProvider AlphabetTrace string // String for the AlphabetTraceProvider
AgreeWithProposedOutput bool // Temporary config if we agree or disagree with the posted output
TxMgrConfig txmgr.CLIConfig TxMgrConfig txmgr.CLIConfig
} }
func NewConfig(l1EthRpc string, func NewConfig(
l1EthRpc string,
GameAddress common.Address, GameAddress common.Address,
AlphabetTrace string, AlphabetTrace string,
AgreeWithProposedOutput bool,
) Config { ) Config {
return Config{ return Config{
L1EthRpc: l1EthRpc, L1EthRpc: l1EthRpc,
GameAddress: GameAddress, GameAddress: GameAddress,
AlphabetTrace: AlphabetTrace, AlphabetTrace: AlphabetTrace,
TxMgrConfig: txmgr.NewCLIConfig(l1EthRpc), TxMgrConfig: txmgr.NewCLIConfig(l1EthRpc),
AgreeWithProposedOutput: AgreeWithProposedOutput,
} }
} }
...@@ -70,9 +74,10 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) { ...@@ -70,9 +74,10 @@ func NewConfigFromCLI(ctx *cli.Context) (*Config, error) {
return &Config{ return &Config{
// Required Flags // Required Flags
L1EthRpc: ctx.String(flags.L1EthRpcFlag.Name), L1EthRpc: ctx.String(flags.L1EthRpcFlag.Name),
GameAddress: dgfAddress, GameAddress: dgfAddress,
AlphabetTrace: ctx.String(flags.AlphabetFlag.Name), AlphabetTrace: ctx.String(flags.AlphabetFlag.Name),
TxMgrConfig: txMgrConfig, AgreeWithProposedOutput: ctx.Bool(flags.AgreeWithProposedOutputFlag.Name),
TxMgrConfig: txMgrConfig,
}, nil }, nil
} }
...@@ -9,13 +9,14 @@ import ( ...@@ -9,13 +9,14 @@ import (
) )
var ( var (
validL1EthRpc = "http://localhost:8545" validL1EthRpc = "http://localhost:8545"
validGameAddress = common.HexToAddress("0x7bdd3b028C4796eF0EAf07d11394d0d9d8c24139") validGameAddress = common.HexToAddress("0x7bdd3b028C4796eF0EAf07d11394d0d9d8c24139")
validAlphabetTrace = "abcdefgh" validAlphabetTrace = "abcdefgh"
agreeWithProposedOutput = true
) )
func validConfig() Config { func validConfig() Config {
cfg := NewConfig(validL1EthRpc, validGameAddress, validAlphabetTrace) cfg := NewConfig(validL1EthRpc, validGameAddress, validAlphabetTrace, agreeWithProposedOutput)
return cfg return cfg
} }
......
...@@ -3,27 +3,28 @@ package fault ...@@ -3,27 +3,28 @@ package fault
import ( import (
"context" "context"
"errors" "errors"
"fmt"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
) )
type Agent struct { type Agent struct {
solver *Solver solver *Solver
trace TraceProvider loader Loader
loader Loader responder Responder
responder Responder maxDepth int
maxDepth int agreeWithProposedOutput bool
log log.Logger log log.Logger
} }
func NewAgent(loader Loader, maxDepth int, trace TraceProvider, responder Responder, log log.Logger) Agent { func NewAgent(loader Loader, maxDepth int, trace TraceProvider, responder Responder, agreeWithProposedOutput bool, log log.Logger) Agent {
return Agent{ return Agent{
solver: NewSolver(maxDepth, trace), solver: NewSolver(maxDepth, trace),
trace: trace, loader: loader,
loader: loader, responder: responder,
responder: responder, maxDepth: maxDepth,
maxDepth: maxDepth, agreeWithProposedOutput: agreeWithProposedOutput,
log: log, log: log,
} }
} }
...@@ -36,11 +37,15 @@ func (a *Agent) Act() error { ...@@ -36,11 +37,15 @@ func (a *Agent) Act() error {
} }
// Create counter claims // Create counter claims
for _, claim := range game.Claims() { for _, claim := range game.Claims() {
_ = a.move(claim, game) if err := a.move(claim, game); err != nil {
log.Error("Failed to move", "err", err)
}
} }
// Step on all leaf claims // Step on all leaf claims
for _, claim := range game.Claims() { for _, claim := range game.Claims() {
_ = a.step(claim, game) if err := a.step(claim, game); err != nil {
log.Error("Failed to step", "err", err)
}
} }
return nil return nil
} }
...@@ -49,34 +54,33 @@ func (a *Agent) Act() error { ...@@ -49,34 +54,33 @@ func (a *Agent) Act() error {
func (a *Agent) newGameFromContracts(ctx context.Context) (Game, error) { func (a *Agent) newGameFromContracts(ctx context.Context) (Game, error) {
claims, err := a.loader.FetchClaims(ctx) claims, err := a.loader.FetchClaims(ctx)
if err != nil { if err != nil {
return nil, err return nil, fmt.Errorf("failed to fetch claims: %w", err)
} }
if len(claims) == 0 { if len(claims) == 0 {
return nil, errors.New("no claims") return nil, errors.New("no claims")
} }
game := NewGameState(claims[0], uint64(a.maxDepth)) game := NewGameState(a.agreeWithProposedOutput, claims[0], uint64(a.maxDepth))
if err := game.PutAll(claims[1:]); err != nil { if err := game.PutAll(claims[1:]); err != nil {
return nil, err return nil, fmt.Errorf("failed to load claims into the local state: %w", err)
} }
return game, nil return game, nil
} }
// move determines & executes the next move given a claim pair // move determines & executes the next move given a claim
func (a *Agent) move(claim Claim, game Game) error { func (a *Agent) move(claim Claim, game Game) error {
a.log.Info("Fetching claims") nextMove, err := a.solver.NextMove(claim, game.AgreeWithClaimLevel(claim))
nextMove, err := a.solver.NextMove(claim)
if err != nil { if err != nil {
a.log.Warn("Failed to execute the next move", "err", err) a.log.Warn("Failed to execute the next move", "err", err)
return err return err
} }
if nextMove == nil { if nextMove == nil {
a.log.Info("No next move") a.log.Debug("No next move")
return nil return nil
} }
move := *nextMove move := *nextMove
log := a.log.New("is_defend", move.DefendsParent(), "depth", move.Depth(), "index_at_depth", move.IndexAtDepth(), "value", move.Value, log := a.log.New("is_defend", move.DefendsParent(), "depth", move.Depth(), "index_at_depth", move.IndexAtDepth(),
"letter", string(move.Value[31:]), "trace_index", move.Value[30], "value", move.Value, "trace_index", move.TraceIndex(a.maxDepth),
"parent_letter", string(claim.Value[31:]), "parent_trace_index", claim.Value[30]) "parent_value", claim.Value, "parent_trace_index", claim.TraceIndex(a.maxDepth))
if game.IsDuplicate(move) { if game.IsDuplicate(move) {
log.Debug("Duplicate move") log.Debug("Duplicate move")
return nil return nil
...@@ -85,25 +89,24 @@ func (a *Agent) move(claim Claim, game Game) error { ...@@ -85,25 +89,24 @@ func (a *Agent) move(claim Claim, game Game) error {
return a.responder.Respond(context.TODO(), move) return a.responder.Respond(context.TODO(), move)
} }
// step attempts to execute the step through the responder // step determines & executes the next step against a leaf claim through the responder
func (a *Agent) step(claim Claim, game Game) error { func (a *Agent) step(claim Claim, game Game) error {
if claim.Depth() != a.maxDepth { if claim.Depth() != a.maxDepth {
return nil return nil
} }
a.log.Info("Attempting step", "claim_depth", claim.Depth(), "maxDepth", a.maxDepth) a.log.Info("Attempting step", "claim_depth", claim.Depth(), "maxDepth", a.maxDepth)
step, err := a.solver.AttemptStep(claim) step, err := a.solver.AttemptStep(claim)
if err != nil { if err != nil {
a.log.Info("Failed to get a step", "err", err) a.log.Warn("Failed to get a step", "err", err)
return err return err
} }
a.log.Info("Performing step", a.log.Info("Performing step", "is_attack", step.IsAttack,
"depth", step.LeafClaim.Depth(), "index_at_depth", step.LeafClaim.IndexAtDepth(), "value", step.LeafClaim.Value, "depth", step.LeafClaim.Depth(), "index_at_depth", step.LeafClaim.IndexAtDepth(), "value", step.LeafClaim.Value)
"is_attack", step.IsAttack)
callData := StepCallData{ callData := StepCallData{
ClaimIndex: uint64(step.LeafClaim.ContractIndex), ClaimIndex: uint64(step.LeafClaim.ContractIndex),
IsAttack: step.IsAttack, IsAttack: step.IsAttack,
StateData: step.PreState,
} }
return a.responder.Step(context.TODO(), callData) return a.responder.Step(context.TODO(), callData)
} }
...@@ -5,8 +5,11 @@ import ( ...@@ -5,8 +5,11 @@ import (
"strings" "strings"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
) )
var _ TraceProvider = (*AlphabetProvider)(nil)
// AlphabetProvider is a [TraceProvider] that provides claims for specific // AlphabetProvider is a [TraceProvider] that provides claims for specific
// indices in the given trace. // indices in the given trace.
type AlphabetProvider struct { type AlphabetProvider struct {
...@@ -32,7 +35,7 @@ func (ap *AlphabetProvider) GetPreimage(i uint64) ([]byte, error) { ...@@ -32,7 +35,7 @@ func (ap *AlphabetProvider) GetPreimage(i uint64) ([]byte, error) {
if i >= uint64(len(ap.state)) { if i >= uint64(len(ap.state)) {
return ap.GetPreimage(uint64(len(ap.state)) - 1) return ap.GetPreimage(uint64(len(ap.state)) - 1)
} }
return buildAlphabetClaimBytes(i, ap.state[i]), nil return BuildAlphabetPreimage(i, ap.state[i]), nil
} }
// Get returns the claim value at the given index in the trace. // Get returns the claim value at the given index in the trace.
...@@ -41,17 +44,31 @@ func (ap *AlphabetProvider) Get(i uint64) (common.Hash, error) { ...@@ -41,17 +44,31 @@ func (ap *AlphabetProvider) Get(i uint64) (common.Hash, error) {
if err != nil { if err != nil {
return common.Hash{}, err return common.Hash{}, err
} }
return common.BytesToHash(claimBytes), nil return crypto.Keccak256Hash(claimBytes), nil
}
func (ap *AlphabetProvider) AbsolutePreState() []byte {
out := make([]byte, 32)
out[31] = 140 // ascii character 140 is "`"
return out
} }
// buildAlphabetClaimBytes constructs the claim bytes for the index and state item. // BuildAlphabetPreimage constructs the claim bytes for the index and state item.
func buildAlphabetClaimBytes(i uint64, letter string) []byte { func BuildAlphabetPreimage(i uint64, letter string) []byte {
return append(IndexToBytes(i), []byte(letter)...) return append(IndexToBytes(i), LetterToBytes(letter)...)
} }
// IndexToBytes converts an index to a byte slice big endian // IndexToBytes converts an index to a byte slice big endian
func IndexToBytes(i uint64) []byte { func IndexToBytes(i uint64) []byte {
big := new(big.Int) big := new(big.Int)
big.SetUint64(i) big.SetUint64(i)
return big.Bytes() out := make([]byte, 32)
return big.FillBytes(out)
}
// LetterToBytes converts a letter to a 32 byte array
func LetterToBytes(letter string) []byte {
out := make([]byte, 32)
out[31] = byte(letter[0])
return out
} }
...@@ -20,15 +20,15 @@ func TestAlphabetProvider_Get_ClaimsByTraceIndex(t *testing.T) { ...@@ -20,15 +20,15 @@ func TestAlphabetProvider_Get_ClaimsByTraceIndex(t *testing.T) {
}{ }{
{ {
7, 7,
common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000768"), alphabetClaim(7, "h"),
}, },
{ {
3, 3,
common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000364"), alphabetClaim(3, "d"),
}, },
{ {
5, 5,
common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000566"), alphabetClaim(5, "f"),
}, },
} }
...@@ -54,7 +54,7 @@ func FuzzIndexToBytes(f *testing.F) { ...@@ -54,7 +54,7 @@ func FuzzIndexToBytes(f *testing.F) {
// returns the correct pre-image for a index. // returns the correct pre-image for a index.
func TestGetPreimage_Succeeds(t *testing.T) { func TestGetPreimage_Succeeds(t *testing.T) {
ap := NewAlphabetProvider("abc", 2) ap := NewAlphabetProvider("abc", 2)
expected := append(IndexToBytes(uint64(0)), []byte("a")...) expected := BuildAlphabetPreimage(0, "a'")
retrieved, err := ap.GetPreimage(uint64(0)) retrieved, err := ap.GetPreimage(uint64(0))
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, expected, retrieved) require.Equal(t, expected, retrieved)
...@@ -73,8 +73,7 @@ func TestGet_Succeeds(t *testing.T) { ...@@ -73,8 +73,7 @@ func TestGet_Succeeds(t *testing.T) {
ap := NewAlphabetProvider("abc", 2) ap := NewAlphabetProvider("abc", 2)
claim, err := ap.Get(0) claim, err := ap.Get(0)
require.NoError(t, err) require.NoError(t, err)
concatenated := append(IndexToBytes(0), []byte("a")...) expected := alphabetClaim(0, "a")
expected := common.BytesToHash(concatenated)
require.Equal(t, expected, claim) require.Equal(t, expected, claim)
} }
...@@ -92,7 +91,6 @@ func TestGet_Extends(t *testing.T) { ...@@ -92,7 +91,6 @@ func TestGet_Extends(t *testing.T) {
ap := NewAlphabetProvider("abc", 2) ap := NewAlphabetProvider("abc", 2)
claim, err := ap.Get(3) claim, err := ap.Get(3)
require.NoError(t, err) require.NoError(t, err)
concatenated := append(IndexToBytes(2), []byte("c")...) expected := alphabetClaim(2, "c")
expected := common.BytesToHash(concatenated)
require.Equal(t, expected, claim) require.Equal(t, expected, claim)
} }
package examples
import (
"os"
"github.com/ethereum-optimism/optimism/op-challenger/fault"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/log"
)
func FullGame() {
log.Root().SetHandler(
log.LvlFilterHandler(log.LvlInfo, log.StreamHandler(os.Stdout, log.TerminalFormat(true))),
)
canonical := "abcdefgh"
disputed := "abcdexyz"
maxDepth := uint64(3)
canonicalProvider := fault.NewAlphabetProvider(canonical, maxDepth)
disputedProvider := fault.NewAlphabetProvider(disputed, maxDepth)
root := fault.Claim{
ClaimData: fault.ClaimData{
Value: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000077a"),
Position: fault.NewPosition(0, 0),
},
}
o := fault.NewOrchestrator(maxDepth, []fault.TraceProvider{canonicalProvider, disputedProvider}, []string{"charlie", "mallory"}, root)
o.Start()
}
package examples
import (
"github.com/ethereum-optimism/optimism/op-challenger/fault"
)
func PositionExampleOne() {
// Example 1
// abcdefgh
// abcdexyz
// go left to d, then right to f, then left to e
p := fault.Position{}
p.Print(3)
p = p.Attack()
p.Print(3)
p = p.Defend()
p.Print(3)
p = p.Attack()
p.Print(3)
}
func PositionExampleTwo() {
// Example 2
// abcdefgh
// abqrstuv
// go left r, then left to b, then right to q
p := fault.Position{}
p.Print(3)
p = p.Attack()
p.Print(3)
p = p.Attack()
p.Print(3)
p = p.Defend()
p.Print(3)
}
package examples
import (
"fmt"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum-optimism/optimism/op-challenger/fault"
)
func PrettyPrintAlphabetClaim(name string, claim fault.Claim) {
value := claim.Value
idx := value[30]
letter := value[31]
if claim.IsRoot() {
fmt.Printf("%s\ttrace %v letter %c\n", name, idx, letter)
} else {
fmt.Printf("%s\ttrace %v letter %c is attack %v\n", name, idx, letter, !claim.DefendsParent())
}
}
// SolverExampleOne uses the [fault.Solver] with a [fault.AlphabetProvider]
// to print out fault game traces for the "abcdexyz" counter-state.
func SolverExampleOne() {
fmt.Println("Solver: Example 1")
// Construct the fault position.
canonical := "abcdefgh"
disputed := "abcdexyz"
maxDepth := 3
// Root claim is z at trace index 7 from the disputed provider
root := fault.Claim{
ClaimData: fault.ClaimData{
Value: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000077a"),
Position: fault.NewPosition(0, 0),
},
}
canonicalProvider := fault.NewAlphabetProvider(canonical, uint64(maxDepth))
disputedProvider := fault.NewAlphabetProvider(disputed, uint64(maxDepth))
// Create a solver with the canonical provider.
cannonicalSolver := fault.NewSolver(maxDepth, canonicalProvider)
disputedSolver := fault.NewSolver(maxDepth, disputedProvider)
// Print the initial state.
fmt.Println("Canonical state: ", canonical)
fmt.Println("Disputed state: ", disputed)
fmt.Println()
fmt.Println("Proceeding with the following moves:")
fmt.Println("go left to d, then right to x (cannonical is f), then left to e")
fmt.Println()
PrettyPrintAlphabetClaim("Root claim", root)
claim1, err := cannonicalSolver.NextMove(root)
if err != nil {
fmt.Printf("error getting claim from provider: %v", err)
}
PrettyPrintAlphabetClaim("Cannonical move", *claim1)
claim2, err := disputedSolver.NextMove(*claim1)
if err != nil {
fmt.Printf("error getting claim from provider: %v", err)
}
PrettyPrintAlphabetClaim("Disputed moved", *claim2)
claim3, err := cannonicalSolver.NextMove(*claim2)
if err != nil {
fmt.Printf("error getting claim from provider: %v", err)
}
PrettyPrintAlphabetClaim("Cannonical move", *claim3)
}
package main
import (
"github.com/ethereum-optimism/optimism/op-challenger/fault/cmd/examples"
)
func main() {
examples.FullGame()
// examples.SolverExampleOne()
// examples.PositionExampleOne()
// examples.PositionExampleTwo()
}
...@@ -26,42 +26,49 @@ type Game interface { ...@@ -26,42 +26,49 @@ type Game interface {
// IsDuplicate returns true if the provided [Claim] already exists in the game state. // IsDuplicate returns true if the provided [Claim] already exists in the game state.
IsDuplicate(claim Claim) bool IsDuplicate(claim Claim) bool
// PreStateClaim gets the claim which commits to the pre-state of this specific claim. // AgreeWithLevel returns if the game state agrees with the provided claim level.
// This will return an error if it is called with a non-leaf claim. AgreeWithClaimLevel(claim Claim) bool
PreStateClaim(claim Claim) (Claim, error)
// PostStateClaim gets the claim which commits to the post-state of this specific claim.
// This will return an error if it is called with a non-leaf claim.
PostStateClaim(claim Claim) (Claim, error)
} }
type extendedClaim struct { type extendedClaim struct {
self Claim self Claim
contractIndex int children []ClaimData
children []ClaimData
} }
// gameState is a struct that represents the state of a dispute game. // gameState is a struct that represents the state of a dispute game.
// The game state implements the [Game] interface. // The game state implements the [Game] interface.
type gameState struct { type gameState struct {
root ClaimData agreeWithProposedOutput bool
claims map[ClaimData]*extendedClaim root ClaimData
depth uint64 claims map[ClaimData]*extendedClaim
depth uint64
} }
// NewGameState returns a new game state. // NewGameState returns a new game state.
// The provided [Claim] is used as the root node. // The provided [Claim] is used as the root node.
func NewGameState(root Claim, depth uint64) *gameState { func NewGameState(agreeWithProposedOutput bool, root Claim, depth uint64) *gameState {
claims := make(map[ClaimData]*extendedClaim) claims := make(map[ClaimData]*extendedClaim)
claims[root.ClaimData] = &extendedClaim{ claims[root.ClaimData] = &extendedClaim{
self: root, self: root,
contractIndex: 0, children: make([]ClaimData, 0),
children: make([]ClaimData, 0),
} }
return &gameState{ return &gameState{
root: root.ClaimData, agreeWithProposedOutput: agreeWithProposedOutput,
claims: claims, root: root.ClaimData,
depth: depth, claims: claims,
depth: depth,
}
}
// AgreeWithLevel returns if the game state agrees with the provided claim level.
func (g *gameState) AgreeWithClaimLevel(claim Claim) bool {
isOddLevel := claim.Depth()%2 == 1
// If we agree with the proposed output, we agree with odd levels
// If we disagree with the proposed output, we agree with the root claim level & even levels
if g.agreeWithProposedOutput {
return isOddLevel
} else {
return !isOddLevel
} }
} }
...@@ -81,15 +88,15 @@ func (g *gameState) Put(claim Claim) error { ...@@ -81,15 +88,15 @@ func (g *gameState) Put(claim Claim) error {
if claim.IsRoot() || g.IsDuplicate(claim) { if claim.IsRoot() || g.IsDuplicate(claim) {
return ErrClaimExists return ErrClaimExists
} }
if parent, ok := g.claims[claim.Parent]; !ok { parent, ok := g.claims[claim.Parent]
if !ok {
return errors.New("no parent claim") return errors.New("no parent claim")
} else { } else {
parent.children = append(parent.children, claim.ClaimData) parent.children = append(parent.children, claim.ClaimData)
} }
g.claims[claim.ClaimData] = &extendedClaim{ g.claims[claim.ClaimData] = &extendedClaim{
self: claim, self: claim,
contractIndex: claim.ContractIndex, children: make([]ClaimData, 0),
children: make([]ClaimData, 0),
} }
return nil return nil
} }
...@@ -125,45 +132,3 @@ func (g *gameState) getParent(claim Claim) (Claim, error) { ...@@ -125,45 +132,3 @@ func (g *gameState) getParent(claim Claim) (Claim, error) {
return parent.self, nil return parent.self, nil
} }
} }
func (g *gameState) PreStateClaim(claim Claim) (Claim, error) {
// Do checks in PreStateClaim because these do not hold while walking the tree
if claim.Depth() != int(g.depth) {
return Claim{}, errors.New("Only leaf claims have pre or post state")
}
// If the claim is the far left most claim, the pre-state is pulled from the contracts & we can supply at contract index.
if claim.IndexAtDepth() == 0 {
return Claim{
ContractIndex: -1,
}, nil
}
return g.preStateClaim(claim)
}
// preStateClaim is the internal tree walker which does not do error handling
func (g *gameState) preStateClaim(claim Claim) (Claim, error) {
parent, _ := g.getParent(claim)
if claim.DefendsParent() {
return parent, nil
} else {
return g.preStateClaim(parent)
}
}
func (g *gameState) PostStateClaim(claim Claim) (Claim, error) {
// Do checks in PostStateClaim because these do not hold while walking the tree
if claim.Depth() != int(g.depth) {
return Claim{}, errors.New("Only leaf claims have pre or post state")
}
return g.postStateClaim(claim)
}
// postStateClaim is the internal tree walker which does not do error handling
func (g *gameState) postStateClaim(claim Claim) (Claim, error) {
parent, _ := g.getParent(claim)
if claim.DefendsParent() {
return g.postStateClaim(parent)
} else {
return parent, nil
}
}
...@@ -48,7 +48,7 @@ func createTestClaims() (Claim, Claim, Claim, Claim) { ...@@ -48,7 +48,7 @@ func createTestClaims() (Claim, Claim, Claim, Claim) {
func TestIsDuplicate(t *testing.T) { func TestIsDuplicate(t *testing.T) {
// Setup the game state. // Setup the game state.
root, top, middle, bottom := createTestClaims() root, top, middle, bottom := createTestClaims()
g := NewGameState(root, testMaxDepth) g := NewGameState(false, root, testMaxDepth)
require.NoError(t, g.Put(top)) require.NoError(t, g.Put(top))
// Root + Top should be duplicates // Root + Top should be duplicates
...@@ -65,7 +65,7 @@ func TestIsDuplicate(t *testing.T) { ...@@ -65,7 +65,7 @@ func TestIsDuplicate(t *testing.T) {
func TestGame_Put_RootAlreadyExists(t *testing.T) { func TestGame_Put_RootAlreadyExists(t *testing.T) {
// Setup the game state. // Setup the game state.
top, _, _, _ := createTestClaims() top, _, _, _ := createTestClaims()
g := NewGameState(top, testMaxDepth) g := NewGameState(false, top, testMaxDepth)
// Try to put the root claim into the game state again. // Try to put the root claim into the game state again.
err := g.Put(top) err := g.Put(top)
...@@ -77,7 +77,7 @@ func TestGame_Put_RootAlreadyExists(t *testing.T) { ...@@ -77,7 +77,7 @@ func TestGame_Put_RootAlreadyExists(t *testing.T) {
func TestGame_PutAll_RootAlreadyExists(t *testing.T) { func TestGame_PutAll_RootAlreadyExists(t *testing.T) {
// Setup the game state. // Setup the game state.
root, _, _, _ := createTestClaims() root, _, _, _ := createTestClaims()
g := NewGameState(root, testMaxDepth) g := NewGameState(false, root, testMaxDepth)
// Try to put the root claim into the game state again. // Try to put the root claim into the game state again.
err := g.PutAll([]Claim{root}) err := g.PutAll([]Claim{root})
...@@ -88,7 +88,7 @@ func TestGame_PutAll_RootAlreadyExists(t *testing.T) { ...@@ -88,7 +88,7 @@ func TestGame_PutAll_RootAlreadyExists(t *testing.T) {
// instance errors when the given claim already exists in state. // instance errors when the given claim already exists in state.
func TestGame_PutAll_AlreadyExists(t *testing.T) { func TestGame_PutAll_AlreadyExists(t *testing.T) {
root, top, middle, bottom := createTestClaims() root, top, middle, bottom := createTestClaims()
g := NewGameState(root, testMaxDepth) g := NewGameState(false, root, testMaxDepth)
err := g.PutAll([]Claim{top, middle}) err := g.PutAll([]Claim{top, middle})
require.NoError(t, err) require.NoError(t, err)
...@@ -101,7 +101,7 @@ func TestGame_PutAll_AlreadyExists(t *testing.T) { ...@@ -101,7 +101,7 @@ func TestGame_PutAll_AlreadyExists(t *testing.T) {
func TestGame_PutAll_ParentsAndChildren(t *testing.T) { func TestGame_PutAll_ParentsAndChildren(t *testing.T) {
// Setup the game state. // Setup the game state.
root, top, middle, bottom := createTestClaims() root, top, middle, bottom := createTestClaims()
g := NewGameState(root, testMaxDepth) g := NewGameState(false, root, testMaxDepth)
// We should not be able to get the parent of the root claim. // We should not be able to get the parent of the root claim.
parent, err := g.getParent(root) parent, err := g.getParent(root)
...@@ -127,7 +127,7 @@ func TestGame_PutAll_ParentsAndChildren(t *testing.T) { ...@@ -127,7 +127,7 @@ func TestGame_PutAll_ParentsAndChildren(t *testing.T) {
func TestGame_Put_AlreadyExists(t *testing.T) { func TestGame_Put_AlreadyExists(t *testing.T) {
// Setup the game state. // Setup the game state.
top, middle, _, _ := createTestClaims() top, middle, _, _ := createTestClaims()
g := NewGameState(top, testMaxDepth) g := NewGameState(false, top, testMaxDepth)
// Put the next claim into state. // Put the next claim into state.
err := g.Put(middle) err := g.Put(middle)
...@@ -142,7 +142,7 @@ func TestGame_Put_AlreadyExists(t *testing.T) { ...@@ -142,7 +142,7 @@ func TestGame_Put_AlreadyExists(t *testing.T) {
func TestGame_Put_ParentsAndChildren(t *testing.T) { func TestGame_Put_ParentsAndChildren(t *testing.T) {
// Setup the game state. // Setup the game state.
root, top, middle, bottom := createTestClaims() root, top, middle, bottom := createTestClaims()
g := NewGameState(root, testMaxDepth) g := NewGameState(false, root, testMaxDepth)
// We should not be able to get the parent of the root claim. // We should not be able to get the parent of the root claim.
parent, err := g.getParent(root) parent, err := g.getParent(root)
...@@ -175,7 +175,7 @@ func TestGame_Put_ParentsAndChildren(t *testing.T) { ...@@ -175,7 +175,7 @@ func TestGame_Put_ParentsAndChildren(t *testing.T) {
func TestGame_ClaimPairs(t *testing.T) { func TestGame_ClaimPairs(t *testing.T) {
// Setup the game state. // Setup the game state.
root, top, middle, bottom := createTestClaims() root, top, middle, bottom := createTestClaims()
g := NewGameState(root, testMaxDepth) g := NewGameState(false, root, testMaxDepth)
// Add top claim to the game state. // Add top claim to the game state.
err := g.Put(top) err := g.Put(top)
...@@ -195,42 +195,26 @@ func TestGame_ClaimPairs(t *testing.T) { ...@@ -195,42 +195,26 @@ func TestGame_ClaimPairs(t *testing.T) {
require.ElementsMatch(t, expected, claims) require.ElementsMatch(t, expected, claims)
} }
// TestPrePostStateOnlyOnLeafClaim tests that if PreStateClaim or PostStateClaim is called with an non-leaf claim func TestAgreeWithClaimLevelDisagreeWithOutput(t *testing.T) {
// those functions return an error. // Setup the game state.
func TestPrePostStateOnlyOnLeafClaim(t *testing.T) {
root, top, middle, bottom := createTestClaims() root, top, middle, bottom := createTestClaims()
g := NewGameState(root, testMaxDepth) g := NewGameState(false, root, testMaxDepth)
require.NoError(t, g.PutAll([]Claim{top, middle, bottom})) require.NoError(t, g.PutAll([]Claim{top, middle, bottom}))
_, err := g.PreStateClaim(middle) require.True(t, g.AgreeWithClaimLevel(root))
require.Error(t, err) require.False(t, g.AgreeWithClaimLevel(top))
_, err = g.PostStateClaim(middle) require.True(t, g.AgreeWithClaimLevel(middle))
require.Error(t, err) require.False(t, g.AgreeWithClaimLevel(bottom))
}
func TestPreStateClaim(t *testing.T) {
root, top, middle, bottom := createTestClaims()
g := NewGameState(root, testMaxDepth)
require.NoError(t, g.Put(top))
require.NoError(t, g.Put(middle))
require.NoError(t, g.Put(bottom))
// Bottom trace index is 4. Pre trace index is then 3
pre, err := g.PreStateClaim(bottom)
require.NoError(t, err)
require.Equal(t, top, pre)
} }
func TestPostStateClaim(t *testing.T) { func TestAgreeWithClaimLevelAgreeWithOutput(t *testing.T) {
// Setup the game state.
root, top, middle, bottom := createTestClaims() root, top, middle, bottom := createTestClaims()
g := NewGameState(root, testMaxDepth) g := NewGameState(true, root, testMaxDepth)
require.NoError(t, g.Put(top)) require.NoError(t, g.PutAll([]Claim{top, middle, bottom}))
require.NoError(t, g.Put(middle))
require.NoError(t, g.Put(bottom))
// Bottom trace index is 4. Post trace index is then 5 require.False(t, g.AgreeWithClaimLevel(root))
post, err := g.PostStateClaim(bottom) require.True(t, g.AgreeWithClaimLevel(top))
require.NoError(t, err) require.False(t, g.AgreeWithClaimLevel(middle))
require.Equal(t, middle, post) require.True(t, g.AgreeWithClaimLevel(bottom))
} }
...@@ -28,18 +28,14 @@ type Loader interface { ...@@ -28,18 +28,14 @@ type Loader interface {
// loader pulls in fault dispute game claim data periodically and over subscriptions. // loader pulls in fault dispute game claim data periodically and over subscriptions.
type loader struct { type loader struct {
log log.Logger log log.Logger
state Game
claimFetcher ClaimFetcher claimFetcher ClaimFetcher
} }
// NewLoader creates a new [loader]. // NewLoader creates a new [loader].
func NewLoader(log log.Logger, state Game, claimFetcher ClaimFetcher) *loader { func NewLoader(log log.Logger, claimFetcher ClaimFetcher) *loader {
return &loader{ return &loader{
log: log, log: log,
state: state,
claimFetcher: claimFetcher, claimFetcher: claimFetcher,
} }
} }
...@@ -60,6 +56,8 @@ func (l *loader) fetchClaim(ctx context.Context, arrIndex uint64) (Claim, error) ...@@ -60,6 +56,8 @@ func (l *loader) fetchClaim(ctx context.Context, arrIndex uint64) (Claim, error)
Value: fetchedClaim.Claim, Value: fetchedClaim.Claim,
Position: NewPositionFromGIndex(fetchedClaim.Position.Uint64()), Position: NewPositionFromGIndex(fetchedClaim.Position.Uint64()),
}, },
ContractIndex: int(arrIndex),
ParentContractIndex: int(fetchedClaim.ParentIndex),
} }
if !claim.IsRootPosition() { if !claim.IsRootPosition() {
......
...@@ -15,46 +15,8 @@ import ( ...@@ -15,46 +15,8 @@ import (
var ( var (
mockClaimDataError = fmt.Errorf("claim data errored") mockClaimDataError = fmt.Errorf("claim data errored")
mockClaimLenError = fmt.Errorf("claim len errored") mockClaimLenError = fmt.Errorf("claim len errored")
mockPutError = fmt.Errorf("put errored")
) )
type mockGameState struct {
putCalled int
putErrors bool
}
func (m *mockGameState) Put(claim Claim) error {
m.putCalled++
if m.putErrors {
return mockPutError
}
return nil
}
func (m *mockGameState) PutAll(claims []Claim) error {
m.putCalled += len(claims)
if m.putErrors {
return mockPutError
}
return nil
}
func (m *mockGameState) Claims() []Claim {
return []Claim{}
}
func (m *mockGameState) IsDuplicate(claim Claim) bool {
return false
}
func (m *mockGameState) PreStateClaim(claim Claim) (Claim, error) {
panic("unimplemented")
}
func (m *mockGameState) PostStateClaim(claim Claim) (Claim, error) {
panic("unimplemented")
}
type mockClaimFetcher struct { type mockClaimFetcher struct {
claimDataError bool claimDataError bool
claimLenError bool claimLenError bool
...@@ -126,7 +88,7 @@ func TestLoader_FetchClaims_Succeeds(t *testing.T) { ...@@ -126,7 +88,7 @@ func TestLoader_FetchClaims_Succeeds(t *testing.T) {
log := testlog.Logger(t, log.LvlError) log := testlog.Logger(t, log.LvlError)
mockClaimFetcher := newMockClaimFetcher() mockClaimFetcher := newMockClaimFetcher()
expectedClaims := mockClaimFetcher.returnClaims expectedClaims := mockClaimFetcher.returnClaims
loader := NewLoader(log, &mockGameState{}, mockClaimFetcher) loader := NewLoader(log, mockClaimFetcher)
claims, err := loader.FetchClaims(context.Background()) claims, err := loader.FetchClaims(context.Background())
require.NoError(t, err) require.NoError(t, err)
require.ElementsMatch(t, []Claim{ require.ElementsMatch(t, []Claim{
...@@ -139,6 +101,7 @@ func TestLoader_FetchClaims_Succeeds(t *testing.T) { ...@@ -139,6 +101,7 @@ func TestLoader_FetchClaims_Succeeds(t *testing.T) {
Value: expectedClaims[0].Claim, Value: expectedClaims[0].Claim,
Position: NewPositionFromGIndex(expectedClaims[0].Position.Uint64()), Position: NewPositionFromGIndex(expectedClaims[0].Position.Uint64()),
}, },
ContractIndex: 0,
}, },
{ {
ClaimData: ClaimData{ ClaimData: ClaimData{
...@@ -149,6 +112,7 @@ func TestLoader_FetchClaims_Succeeds(t *testing.T) { ...@@ -149,6 +112,7 @@ func TestLoader_FetchClaims_Succeeds(t *testing.T) {
Value: expectedClaims[0].Claim, Value: expectedClaims[0].Claim,
Position: NewPositionFromGIndex(expectedClaims[1].Position.Uint64()), Position: NewPositionFromGIndex(expectedClaims[1].Position.Uint64()),
}, },
ContractIndex: 1,
}, },
{ {
ClaimData: ClaimData{ ClaimData: ClaimData{
...@@ -159,6 +123,7 @@ func TestLoader_FetchClaims_Succeeds(t *testing.T) { ...@@ -159,6 +123,7 @@ func TestLoader_FetchClaims_Succeeds(t *testing.T) {
Value: expectedClaims[0].Claim, Value: expectedClaims[0].Claim,
Position: NewPositionFromGIndex(expectedClaims[2].Position.Uint64()), Position: NewPositionFromGIndex(expectedClaims[2].Position.Uint64()),
}, },
ContractIndex: 2,
}, },
}, claims) }, claims)
} }
...@@ -169,7 +134,7 @@ func TestLoader_FetchClaims_ClaimDataErrors(t *testing.T) { ...@@ -169,7 +134,7 @@ func TestLoader_FetchClaims_ClaimDataErrors(t *testing.T) {
log := testlog.Logger(t, log.LvlError) log := testlog.Logger(t, log.LvlError)
mockClaimFetcher := newMockClaimFetcher() mockClaimFetcher := newMockClaimFetcher()
mockClaimFetcher.claimDataError = true mockClaimFetcher.claimDataError = true
loader := NewLoader(log, &mockGameState{}, mockClaimFetcher) loader := NewLoader(log, mockClaimFetcher)
claims, err := loader.FetchClaims(context.Background()) claims, err := loader.FetchClaims(context.Background())
require.ErrorIs(t, err, mockClaimDataError) require.ErrorIs(t, err, mockClaimDataError)
require.Empty(t, claims) require.Empty(t, claims)
...@@ -181,7 +146,7 @@ func TestLoader_FetchClaims_ClaimLenErrors(t *testing.T) { ...@@ -181,7 +146,7 @@ func TestLoader_FetchClaims_ClaimLenErrors(t *testing.T) {
log := testlog.Logger(t, log.LvlError) log := testlog.Logger(t, log.LvlError)
mockClaimFetcher := newMockClaimFetcher() mockClaimFetcher := newMockClaimFetcher()
mockClaimFetcher.claimLenError = true mockClaimFetcher.claimLenError = true
loader := NewLoader(log, &mockGameState{}, mockClaimFetcher) loader := NewLoader(log, mockClaimFetcher)
claims, err := loader.FetchClaims(context.Background()) claims, err := loader.FetchClaims(context.Background())
require.ErrorIs(t, err, mockClaimLenError) require.ErrorIs(t, err, mockClaimLenError)
require.Empty(t, claims) require.Empty(t, claims)
......
package fault
import (
"context"
"github.com/ethereum/go-ethereum/log"
)
type Orchestrator struct {
agents []Agent
claims []Claim
steps []StepCallData
// tracking when to exit
claimLen, stepLen, step int
}
func NewOrchestrator(maxDepth uint64, traces []TraceProvider, names []string, root Claim) Orchestrator {
o := Orchestrator{
agents: make([]Agent, len(traces)),
claims: []Claim{root},
steps: make([]StepCallData, 0),
}
log.Info("Starting game", "root_letter", string(root.Value[31:]))
for i, trace := range traces {
o.agents[i] = NewAgent(&o, int(maxDepth), trace, &o, log.New("role", names[i]))
}
return o
}
func (o *Orchestrator) Respond(_ context.Context, response Claim) error {
response.ContractIndex = len(o.claims)
o.claims = append(o.claims, response)
return nil
}
func (o *Orchestrator) Step(_ context.Context, stepData StepCallData) error {
log.Info("Step recorded", "step", stepData)
o.steps = append(o.steps, stepData)
return nil
}
func (o *Orchestrator) FetchClaims(ctx context.Context) ([]Claim, error) {
c := make([]Claim, len(o.claims))
copy(c, o.claims)
return c, nil
}
func (o *Orchestrator) Start() {
for {
for _, a := range o.agents {
_ = a.Act()
}
if o.shouldExit() {
log.Info("exiting")
return
}
}
}
func (o *Orchestrator) shouldExit() bool {
cl := o.claimLen
sl := o.stepLen
o.claimLen = len(o.claims)
o.stepLen = len(o.steps)
noProgress := o.claimLen == cl && o.stepLen == sl
if noProgress {
o.step = o.step + 1
} else {
o.step = 0
}
return noProgress && o.step == 1
}
...@@ -36,27 +36,29 @@ type testNodeInfo struct { ...@@ -36,27 +36,29 @@ type testNodeInfo struct {
Depth int Depth int
IndexAtDepth int IndexAtDepth int
TraceIndex uint64 TraceIndex uint64
AttackGIndex uint64 // 0 indicates attack is not possible from this node
DefendGIndex uint64 // 0 indicates defend is not possible from this node
} }
var treeNodesMaxDepth4 = []testNodeInfo{ var treeNodesMaxDepth4 = []testNodeInfo{
{GIndex: 1, Depth: 0, IndexAtDepth: 0, TraceIndex: 15}, {GIndex: 1, Depth: 0, IndexAtDepth: 0, TraceIndex: 15, AttackGIndex: 2},
{GIndex: 2, Depth: 1, IndexAtDepth: 0, TraceIndex: 7}, {GIndex: 2, Depth: 1, IndexAtDepth: 0, TraceIndex: 7, AttackGIndex: 4, DefendGIndex: 6},
{GIndex: 3, Depth: 1, IndexAtDepth: 1, TraceIndex: 15}, {GIndex: 3, Depth: 1, IndexAtDepth: 1, TraceIndex: 15, AttackGIndex: 6},
{GIndex: 4, Depth: 2, IndexAtDepth: 0, TraceIndex: 3}, {GIndex: 4, Depth: 2, IndexAtDepth: 0, TraceIndex: 3, AttackGIndex: 8, DefendGIndex: 10},
{GIndex: 5, Depth: 2, IndexAtDepth: 1, TraceIndex: 7}, {GIndex: 5, Depth: 2, IndexAtDepth: 1, TraceIndex: 7, AttackGIndex: 10},
{GIndex: 6, Depth: 2, IndexAtDepth: 2, TraceIndex: 11}, {GIndex: 6, Depth: 2, IndexAtDepth: 2, TraceIndex: 11, AttackGIndex: 12, DefendGIndex: 14},
{GIndex: 7, Depth: 2, IndexAtDepth: 3, TraceIndex: 15}, {GIndex: 7, Depth: 2, IndexAtDepth: 3, TraceIndex: 15, AttackGIndex: 14},
{GIndex: 8, Depth: 3, IndexAtDepth: 0, TraceIndex: 1}, {GIndex: 8, Depth: 3, IndexAtDepth: 0, TraceIndex: 1, AttackGIndex: 16, DefendGIndex: 18},
{GIndex: 9, Depth: 3, IndexAtDepth: 1, TraceIndex: 3}, {GIndex: 9, Depth: 3, IndexAtDepth: 1, TraceIndex: 3, AttackGIndex: 18},
{GIndex: 10, Depth: 3, IndexAtDepth: 2, TraceIndex: 5}, {GIndex: 10, Depth: 3, IndexAtDepth: 2, TraceIndex: 5, AttackGIndex: 20, DefendGIndex: 22},
{GIndex: 11, Depth: 3, IndexAtDepth: 3, TraceIndex: 7}, {GIndex: 11, Depth: 3, IndexAtDepth: 3, TraceIndex: 7, AttackGIndex: 22},
{GIndex: 12, Depth: 3, IndexAtDepth: 4, TraceIndex: 9}, {GIndex: 12, Depth: 3, IndexAtDepth: 4, TraceIndex: 9, AttackGIndex: 24, DefendGIndex: 26},
{GIndex: 13, Depth: 3, IndexAtDepth: 5, TraceIndex: 11}, {GIndex: 13, Depth: 3, IndexAtDepth: 5, TraceIndex: 11, AttackGIndex: 26},
{GIndex: 14, Depth: 3, IndexAtDepth: 6, TraceIndex: 13}, {GIndex: 14, Depth: 3, IndexAtDepth: 6, TraceIndex: 13, AttackGIndex: 28, DefendGIndex: 30},
{GIndex: 15, Depth: 3, IndexAtDepth: 7, TraceIndex: 15}, {GIndex: 15, Depth: 3, IndexAtDepth: 7, TraceIndex: 15, AttackGIndex: 30},
{GIndex: 16, Depth: 4, IndexAtDepth: 0, TraceIndex: 0}, {GIndex: 16, Depth: 4, IndexAtDepth: 0, TraceIndex: 0},
{GIndex: 17, Depth: 4, IndexAtDepth: 1, TraceIndex: 1}, {GIndex: 17, Depth: 4, IndexAtDepth: 1, TraceIndex: 1},
...@@ -95,3 +97,25 @@ func TestTraceIndex(t *testing.T) { ...@@ -95,3 +97,25 @@ func TestTraceIndex(t *testing.T) {
require.Equal(t, test.TraceIndex, result) require.Equal(t, test.TraceIndex, result)
} }
} }
func TestAttack(t *testing.T) {
for _, test := range treeNodesMaxDepth4 {
if test.AttackGIndex == 0 {
continue
}
pos := NewPosition(test.Depth, test.IndexAtDepth)
result := pos.Attack()
require.Equalf(t, test.AttackGIndex, result.ToGIndex(), "Attack from GIndex %v", pos.ToGIndex())
}
}
func TestDefend(t *testing.T) {
for _, test := range treeNodesMaxDepth4 {
if test.DefendGIndex == 0 {
continue
}
pos := NewPosition(test.Depth, test.IndexAtDepth)
result := pos.Defend()
require.Equalf(t, test.DefendGIndex, result.ToGIndex(), "Defend from GIndex %v", pos.ToGIndex())
}
}
...@@ -9,7 +9,6 @@ import ( ...@@ -9,7 +9,6 @@ import (
// Solver uses a [TraceProvider] to determine the moves to make in a dispute game. // Solver uses a [TraceProvider] to determine the moves to make in a dispute game.
type Solver struct { type Solver struct {
TraceProvider TraceProvider
gameDepth int gameDepth int
} }
...@@ -22,7 +21,11 @@ func NewSolver(gameDepth int, traceProvider TraceProvider) *Solver { ...@@ -22,7 +21,11 @@ func NewSolver(gameDepth int, traceProvider TraceProvider) *Solver {
} }
// NextMove returns the next move to make given the current state of the game. // NextMove returns the next move to make given the current state of the game.
func (s *Solver) NextMove(claim Claim) (*Claim, error) { func (s *Solver) NextMove(claim Claim, agreeWithClaimLevel bool) (*Claim, error) {
if agreeWithClaimLevel {
return nil, nil
}
// Special case of the root claim // Special case of the root claim
if claim.IsRoot() { if claim.IsRoot() {
return s.handleRoot(claim) return s.handleRoot(claim)
...@@ -30,33 +33,14 @@ func (s *Solver) NextMove(claim Claim) (*Claim, error) { ...@@ -30,33 +33,14 @@ func (s *Solver) NextMove(claim Claim) (*Claim, error) {
return s.handleMiddle(claim) return s.handleMiddle(claim)
} }
type StepData struct {
LeafClaim Claim
IsAttack bool
}
// AttemptStep determines what step should occur for a given leaf claim.
// An error will be returned if the claim is not at the max depth.
func (s *Solver) AttemptStep(claim Claim) (StepData, error) {
if claim.Depth() != s.gameDepth {
return StepData{}, errors.New("cannot step on non-leaf claims")
}
claimCorrect, err := s.agreeWithClaim(claim.ClaimData)
if err != nil {
return StepData{}, err
}
return StepData{
LeafClaim: claim,
IsAttack: claimCorrect,
}, nil
}
func (s *Solver) handleRoot(claim Claim) (*Claim, error) { func (s *Solver) handleRoot(claim Claim) (*Claim, error) {
agree, err := s.agreeWithClaim(claim.ClaimData) agree, err := s.agreeWithClaim(claim.ClaimData)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Attack the root claim if we do not agree with it // Attack the root claim if we do not agree with it
// Note: We always disagree with the claim level at this point,
// so if we agree with claim maybe we should also attack?
if !agree { if !agree {
return s.attack(claim) return s.attack(claim)
} else { } else {
...@@ -65,10 +49,6 @@ func (s *Solver) handleRoot(claim Claim) (*Claim, error) { ...@@ -65,10 +49,6 @@ func (s *Solver) handleRoot(claim Claim) (*Claim, error) {
} }
func (s *Solver) handleMiddle(claim Claim) (*Claim, error) { func (s *Solver) handleMiddle(claim Claim) (*Claim, error) {
parentCorrect, err := s.agreeWithClaim(claim.Parent)
if err != nil {
return nil, err
}
claimCorrect, err := s.agreeWithClaim(claim.ClaimData) claimCorrect, err := s.agreeWithClaim(claim.ClaimData)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -76,25 +56,50 @@ func (s *Solver) handleMiddle(claim Claim) (*Claim, error) { ...@@ -76,25 +56,50 @@ func (s *Solver) handleMiddle(claim Claim) (*Claim, error) {
if claim.Depth() == s.gameDepth { if claim.Depth() == s.gameDepth {
return nil, errors.New("game depth reached") return nil, errors.New("game depth reached")
} }
if parentCorrect && claimCorrect { if claimCorrect {
// We agree with the parent, but the claim is disagreeing with it.
// Since we agree with the claim, the difference must be to the right of the claim
return s.defend(claim) return s.defend(claim)
} else if parentCorrect && !claimCorrect { } else {
// We agree with the parent, but the claim disagrees with it.
// Since we disagree with the claim, the difference must be to the left of the claim
return s.attack(claim)
} else if !parentCorrect && claimCorrect {
// Do nothing, we disagree with the parent, but this claim has correctly countered it
return nil, nil
} else if !parentCorrect && !claimCorrect {
// We disagree with the parent so want to counter it (which the claim is doing)
// but we also disagree with the claim so there must be a difference to the left of claim
// Note that we will create the correct counter-claim for parent when it is evaluated, no need to do it here
return s.attack(claim) return s.attack(claim)
} }
// This should not be reached }
return nil, errors.New("no next move")
type StepData struct {
LeafClaim Claim
IsAttack bool
PreState []byte
}
// AttemptStep determines what step should occur for a given leaf claim.
// An error will be returned if the claim is not at the max depth.
func (s *Solver) AttemptStep(claim Claim) (StepData, error) {
if claim.Depth() != s.gameDepth {
return StepData{}, errors.New("cannot step on non-leaf claims")
}
claimCorrect, err := s.agreeWithClaim(claim.ClaimData)
if err != nil {
return StepData{}, err
}
index := claim.TraceIndex(s.gameDepth)
var preState []byte
// If we are attacking index 0, we provide the absolute pre-state, not an intermediate state
if index == 0 && !claimCorrect {
preState = s.AbsolutePreState()
} else {
// If attacking, get the state just before, other get the state after
if !claimCorrect {
index = index - 1
}
preState, err = s.GetPreimage(index)
if err != nil {
return StepData{}, err
}
}
return StepData{
LeafClaim: claim,
IsAttack: !claimCorrect,
PreState: preState,
}, nil
} }
// attack returns a response that attacks the claim. // attack returns a response that attacks the claim.
...@@ -105,8 +110,9 @@ func (s *Solver) attack(claim Claim) (*Claim, error) { ...@@ -105,8 +110,9 @@ func (s *Solver) attack(claim Claim) (*Claim, error) {
return nil, err return nil, err
} }
return &Claim{ return &Claim{
ClaimData: ClaimData{Value: value, Position: position}, ClaimData: ClaimData{Value: value, Position: position},
Parent: claim.ClaimData, Parent: claim.ClaimData,
ParentContractIndex: claim.ContractIndex,
}, nil }, nil
} }
...@@ -118,8 +124,9 @@ func (s *Solver) defend(claim Claim) (*Claim, error) { ...@@ -118,8 +124,9 @@ func (s *Solver) defend(claim Claim) (*Claim, error) {
return nil, err return nil, err
} }
return &Claim{ return &Claim{
ClaimData: ClaimData{Value: value, Position: position}, ClaimData: ClaimData{Value: value, Position: position},
Parent: claim.ClaimData, Parent: claim.ClaimData,
ParentContractIndex: claim.ContractIndex,
}, nil }, nil
} }
......
...@@ -4,9 +4,14 @@ import ( ...@@ -4,9 +4,14 @@ import (
"testing" "testing"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
func alphabetClaim(index uint64, letter string) common.Hash {
return crypto.Keccak256Hash(BuildAlphabetPreimage(index, letter))
}
// TestSolver_NextMove_Opponent tests the [Solver] NextMove function // TestSolver_NextMove_Opponent tests the [Solver] NextMove function
// with an [fault.AlphabetProvider] as the [TraceProvider]. // with an [fault.AlphabetProvider] as the [TraceProvider].
func TestSolver_NextMove_Opponent(t *testing.T) { func TestSolver_NextMove_Opponent(t *testing.T) {
...@@ -18,82 +23,106 @@ func TestSolver_NextMove_Opponent(t *testing.T) { ...@@ -18,82 +23,106 @@ func TestSolver_NextMove_Opponent(t *testing.T) {
// The following claims are created using the state: "abcdexyz". // The following claims are created using the state: "abcdexyz".
// The responses are the responses we expect from the solver. // The responses are the responses we expect from the solver.
indices := []struct { indices := []struct {
traceIndex int claim Claim
claim Claim response ClaimData
response ClaimData
}{ }{
{ {
7,
Claim{ Claim{
ClaimData: ClaimData{ ClaimData: ClaimData{
Value: common.HexToHash("0x000000000000000000000000000000000000000000000000000000000000077a"), Value: alphabetClaim(7, "z"),
Position: NewPosition(0, 0), Position: NewPosition(0, 0),
}, },
// Root claim has no parent // Root claim has no parent
}, },
ClaimData{ ClaimData{
Value: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000364"), Value: alphabetClaim(3, "d"),
Position: NewPosition(1, 0), Position: NewPosition(1, 0),
}, },
}, },
{ {
3,
Claim{ Claim{
ClaimData: ClaimData{ ClaimData: ClaimData{
Value: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000364"), Value: alphabetClaim(3, "d"),
Position: NewPosition(1, 0), Position: NewPosition(1, 0),
}, },
Parent: ClaimData{ Parent: ClaimData{
Value: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000768"), Value: alphabetClaim(7, "h"),
Position: NewPosition(0, 0), Position: NewPosition(0, 0),
}, },
}, },
ClaimData{ ClaimData{
Value: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000566"), Value: alphabetClaim(5, "f"),
Position: NewPosition(2, 2), Position: NewPosition(2, 2),
}, },
}, },
{ {
5,
Claim{ Claim{
ClaimData: ClaimData{ ClaimData: ClaimData{
Value: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000578"), Value: alphabetClaim(5, "x"),
Position: NewPosition(2, 2), Position: NewPosition(2, 2),
}, },
Parent: ClaimData{ Parent: ClaimData{
Value: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000768"), Value: alphabetClaim(7, "h"),
Position: NewPosition(1, 1), Position: NewPosition(1, 1),
}, },
}, },
ClaimData{ ClaimData{
Value: common.HexToHash("0x0000000000000000000000000000000000000000000000000000000000000465"), Value: alphabetClaim(4, "e"),
Position: NewPosition(3, 4), Position: NewPosition(3, 4),
}, },
}, },
} }
for _, test := range indices { for _, test := range indices {
res, err := solver.NextMove(test.claim) res, err := solver.NextMove(test.claim, false)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, test.response, res.ClaimData) require.Equal(t, test.response, res.ClaimData)
} }
} }
func TestNoMoveAgainstOwnLevel(t *testing.T) {
maxDepth := 3
mallory := NewAlphabetProvider("abcdepqr", uint64(maxDepth))
solver := NewSolver(maxDepth, mallory)
claim := Claim{
ClaimData: ClaimData{
Value: alphabetClaim(7, "z"),
Position: NewPosition(0, 0),
},
// Root claim has no parent
}
move, err := solver.NextMove(claim, true)
require.Nil(t, move)
require.Nil(t, err)
}
func TestAttemptStep(t *testing.T) { func TestAttemptStep(t *testing.T) {
maxDepth := 3 maxDepth := 3
canonicalProvider := NewAlphabetProvider("abcdefgh", uint64(maxDepth)) canonicalProvider := NewAlphabetProvider("abcdefgh", uint64(maxDepth))
solver := NewSolver(maxDepth, canonicalProvider) solver := NewSolver(maxDepth, canonicalProvider)
root, top, middle, bottom := createTestClaims() _, _, middle, bottom := createTestClaims()
g := NewGameState(root, testMaxDepth)
require.NoError(t, g.Put(top)) zero := Claim{
require.NoError(t, g.Put(middle)) ClaimData: ClaimData{
require.NoError(t, g.Put(bottom)) // Zero value is a purposely disagree with claim value "a"
Position: NewPosition(3, 0),
},
}
step, err := solver.AttemptStep(bottom) step, err := solver.AttemptStep(bottom)
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, bottom, step.LeafClaim) require.Equal(t, bottom, step.LeafClaim)
require.True(t, step.IsAttack) require.True(t, step.IsAttack)
require.Equal(t, step.PreState, BuildAlphabetPreimage(3, "d"))
_, err = solver.AttemptStep(middle) _, err = solver.AttemptStep(middle)
require.Error(t, err) require.Error(t, err)
step, err = solver.AttemptStep(zero)
require.NoError(t, err)
require.Equal(t, zero, step.LeafClaim)
require.True(t, step.IsAttack)
require.Equal(t, canonicalProvider.AbsolutePreState(), step.PreState)
} }
...@@ -22,10 +22,12 @@ type StepCallData struct { ...@@ -22,10 +22,12 @@ type StepCallData struct {
// TraceProvider is a generic way to get a claim value at a specific // TraceProvider is a generic way to get a claim value at a specific
// step in the trace. // step in the trace.
// The [AlphabetProvider] is a minimal implementation of this interface. // Get(i) = Keccak256(GetPreimage(i))
// AbsolutePreState is the value of the trace that transitions to the trace value at index 0
type TraceProvider interface { type TraceProvider interface {
Get(i uint64) (common.Hash, error) Get(i uint64) (common.Hash, error)
GetPreimage(i uint64) ([]byte, error) GetPreimage(i uint64) ([]byte, error)
AbsolutePreState() []byte
} }
// ClaimData is the core of a claim. It must be unique inside a specific game. // ClaimData is the core of a claim. It must be unique inside a specific game.
......
...@@ -33,6 +33,11 @@ var ( ...@@ -33,6 +33,11 @@ var (
Usage: "Alphabet Trace (temporary)", Usage: "Alphabet Trace (temporary)",
EnvVars: prefixEnvVars("ALPHABET"), EnvVars: prefixEnvVars("ALPHABET"),
} }
AgreeWithProposedOutputFlag = &cli.BoolFlag{
Name: "agree-with-proposed-output",
Usage: "Temporary hardcoded flag if we agree or disagree with the proposed output.",
EnvVars: prefixEnvVars("AGREE_WITH_PROPOSED_OUTPUT"),
}
// Optional Flags // Optional Flags
) )
...@@ -41,6 +46,7 @@ var requiredFlags = []cli.Flag{ ...@@ -41,6 +46,7 @@ var requiredFlags = []cli.Flag{
L1EthRpcFlag, L1EthRpcFlag,
DGFAddressFlag, DGFAddressFlag,
AlphabetFlag, AlphabetFlag,
AgreeWithProposedOutputFlag,
} }
// optionalFlags is a list of unchecked cli flags // optionalFlags is a list of unchecked cli flags
......
#!/bin/bash
set -euo pipefail
DIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)
cd "$DIR"
# build the challenger to keep it up to date
make
cd ..
make devnet-clean
make devnet-up-deploy
DEVNET_SPONSOR="ac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"
DISPUTE_GAME_PROXY="0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e"
CHARLIE_ADDRESS="0xF45B7537828CB2fffBC69996B054c2Aaf36DC778"
CHARLIE_KEY="74feb147d72bfae943e6b4e483410933d9e447d5dc47d52432dcc2c1454dabb7"
MALLORY_ADDRESS="0x4641c704a6c743f73ee1f36C7568Fbf4b80681e4"
MALLORY_KEY="28d7045146193f5f4eeb151c4843544b1b0d30a7ac1680c845a416fac65a7715"
echo "----------------------------------------------------------------"
echo " - Fetching balance of the sponsor"
echo " - Balance: $(cast balance 0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266)"
echo "----------------------------------------------------------------"
echo "Funding Charlie"
cast send $CHARLIE_ADDRESS --value 5ether --private-key $DEVNET_SPONSOR
echo "Funding Mallory"
cast send $MALLORY_ADDRESS --value 5ether --private-key $DEVNET_SPONSOR
# Fault game type = 0
GAME_TYPE=0
# Root claim commits to the entire trace.
# Alphabet game claim construction: keccak256(abi.encode(trace_index, trace[trace_index]))
ROOT_CLAIM=$(cast keccak $(cast abi-encode "f(uint256,uint256)" 15 122))
# Extra data is a dynamic `bytes` type that contains the L2 Block Number of the output proposal that the root claim disagrees with
# Doesn't matter right now since we're not deleting outputs, so just set it to 1
EXTRA_DATA=$(cast to-bytes32 1)
echo "Initializing the game"
cast call --private-key $MALLORY_KEY $DISPUTE_GAME_PROXY "create(uint8,bytes32,bytes)" $GAME_TYPE $ROOT_CLAIM $EXTRA_DATA
cast send --private-key $MALLORY_KEY $DISPUTE_GAME_PROXY "create(uint8,bytes32,bytes)" $GAME_TYPE $ROOT_CLAIM $EXTRA_DATA
#!/bin/bash
set -euo pipefail
DIR=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)
cd "$DIR"
DISPUTE_GAME_PROXY="0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e"
CHARLIE_ADDRESS="0xF45B7537828CB2fffBC69996B054c2Aaf36DC778"
CHARLIE_KEY="74feb147d72bfae943e6b4e483410933d9e447d5dc47d52432dcc2c1454dabb7"
MALLORY_ADDRESS="0x4641c704a6c743f73ee1f36C7568Fbf4b80681e4"
MALLORY_KEY="28d7045146193f5f4eeb151c4843544b1b0d30a7ac1680c845a416fac65a7715"
FAULT_GAME_ADDRESS="0x8daf17a20c9dba35f005b6324f493785d239719d"
./bin/op-challenger --l1-eth-rpc http://localhost:8545 --alphabet "abcdexyz" --game-address $FAULT_GAME_ADDRESS --private-key $MALLORY_KEY --num-confirmations 1 --agree-with-proposed-output=false
#!/bin/bash
set -euo pipefail
DISPUTE_GAME_PROXY="0xB7f8BC63BbcaD18155201308C8f3540b07f84F5e"
FAULT_GAME_ADDRESS="0x8daf17a20c9dba35f005b6324f493785d239719d"
dir=$(cd $(dirname "${BASH_SOURCE[0]}") && pwd)
cd "$dir"
cd ../packages/contracts-bedrock
forge script scripts/FaultDisputeGameViz.s.sol --sig "remote(address)" $FAULT_GAME_ADDRESS --fork-url http://localhost:8545
mv dispute_game.svg "$dir"
...@@ -76,7 +76,7 @@ func TestERC20BridgeDeposits(t *testing.T) { ...@@ -76,7 +76,7 @@ func TestERC20BridgeDeposits(t *testing.T) {
// Approve WETH9 with the bridge // Approve WETH9 with the bridge
tx, err = WETH9.Approve(opts, predeploys.DevL1StandardBridgeAddr, new(big.Int).SetUint64(math.MaxUint64)) tx, err = WETH9.Approve(opts, predeploys.DevL1StandardBridgeAddr, new(big.Int).SetUint64(math.MaxUint64))
require.NoError(t, err) require.NoError(t, err)
_, err = waitForTransaction(tx.Hash(), l1Client, 3*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second) _, err = waitForTransaction(tx.Hash(), l1Client, 6*time.Duration(cfg.DeployConfig.L1BlockTime)*time.Second)
require.NoError(t, err) require.NoError(t, err)
// Bridge the WETH9 // Bridge the WETH9
......
...@@ -300,23 +300,25 @@ func createGethNode(l2 bool, nodeCfg *node.Config, ethCfg *ethconfig.Config, pri ...@@ -300,23 +300,25 @@ func createGethNode(l2 bool, nodeCfg *node.Config, ethCfg *ethconfig.Config, pri
return nil, nil, err return nil, nil, err
} }
keydir := n.KeyStoreDir() if !l2 {
scryptN := 2 keydir := n.KeyStoreDir()
scryptP := 1 scryptN := 2
n.AccountManager().AddBackend(keystore.NewKeyStore(keydir, scryptN, scryptP)) scryptP := 1
ks := n.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) n.AccountManager().AddBackend(keystore.NewKeyStore(keydir, scryptN, scryptP))
ks := n.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore)
password := "foobar"
for _, pk := range privateKeys { password := "foobar"
act, err := ks.ImportECDSA(pk, password) for _, pk := range privateKeys {
if err != nil { act, err := ks.ImportECDSA(pk, password)
n.Close() if err != nil {
return nil, nil, err n.Close()
} return nil, nil, err
err = ks.Unlock(act, password) }
if err != nil { err = ks.Unlock(act, password)
n.Close() if err != nil {
return nil, nil, err n.Close()
return nil, nil, err
}
} }
} }
...@@ -341,5 +343,4 @@ func createGethNode(l2 bool, nodeCfg *node.Config, ethCfg *ethconfig.Config, pri ...@@ -341,5 +343,4 @@ func createGethNode(l2 bool, nodeCfg *node.Config, ethCfg *ethconfig.Config, pri
} }
} }
return n, backend, nil return n, backend, nil
} }
...@@ -1279,7 +1279,7 @@ func TestStopStartBatcher(t *testing.T) { ...@@ -1279,7 +1279,7 @@ func TestStopStartBatcher(t *testing.T) {
receipt := sendTx() receipt := sendTx()
// wait until the block the tx was first included in shows up in the safe chain on the verifier // wait until the block the tx was first included in shows up in the safe chain on the verifier
safeBlockInclusionDuration := time.Duration(3*cfg.DeployConfig.L1BlockTime) * time.Second safeBlockInclusionDuration := time.Duration(6*cfg.DeployConfig.L1BlockTime) * time.Second
_, err = waitForBlock(receipt.BlockNumber, l2Verif, safeBlockInclusionDuration) _, err = waitForBlock(receipt.BlockNumber, l2Verif, safeBlockInclusionDuration)
require.Nil(t, err, "Waiting for block on verifier") require.Nil(t, err, "Waiting for block on verifier")
......
...@@ -291,7 +291,8 @@ var ( ...@@ -291,7 +291,8 @@ var (
} }
SyncReqRespFlag = &cli.BoolFlag{ SyncReqRespFlag = &cli.BoolFlag{
Name: "p2p.sync.req-resp", Name: "p2p.sync.req-resp",
Usage: "Enables experimental P2P req-resp alternative sync method, on both server and client side.", Usage: "Enables P2P req-resp alternative sync method, on both server and client side.",
Value: true,
Required: false, Required: false,
EnvVars: p2pEnv("SYNC_REQ_RESP"), EnvVars: p2pEnv("SYNC_REQ_RESP"),
} }
......
...@@ -59,7 +59,11 @@ func (cfg *L2EndpointConfig) Setup(ctx context.Context, log log.Logger, rollupCf ...@@ -59,7 +59,11 @@ func (cfg *L2EndpointConfig) Setup(ctx context.Context, log log.Logger, rollupCf
return nil, nil, err return nil, nil, err
} }
auth := rpc.WithHTTPAuth(gn.NewJWTAuth(cfg.L2EngineJWTSecret)) auth := rpc.WithHTTPAuth(gn.NewJWTAuth(cfg.L2EngineJWTSecret))
l2Node, err := client.NewRPC(ctx, log, cfg.L2EngineAddr, client.WithGethRPCOptions(auth)) opts := []client.RPCOption{
client.WithGethRPCOptions(auth),
client.WithDialBackoff(10),
}
l2Node, err := client.NewRPC(ctx, log, cfg.L2EngineAddr, opts...)
if err != nil { if err != nil {
return nil, nil, err return nil, nil, err
} }
......
...@@ -27,7 +27,7 @@ type Frame struct { ...@@ -27,7 +27,7 @@ type Frame struct {
ID ChannelID `json:"id"` ID ChannelID `json:"id"`
FrameNumber uint16 `json:"frame_number"` FrameNumber uint16 `json:"frame_number"`
Data []byte `json:"data"` Data []byte `json:"data"`
IsLast bool `'json:"is_last"` IsLast bool `json:"is_last"`
} }
// MarshalBinary writes the frame to `w`. // MarshalBinary writes the frame to `w`.
......
...@@ -2,7 +2,7 @@ FROM ethereum/client-go:v1.11.2 ...@@ -2,7 +2,7 @@ FROM ethereum/client-go:v1.11.2
RUN apk add --no-cache jq RUN apk add --no-cache jq
COPY entrypoint.sh /entrypoint.sh COPY entrypoint-l1.sh /entrypoint.sh
VOLUME ["/db"] VOLUME ["/db"]
......
...@@ -2,7 +2,7 @@ FROM us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:optimism ...@@ -2,7 +2,7 @@ FROM us-docker.pkg.dev/oplabs-tools-artifacts/images/op-geth:optimism
RUN apk add --no-cache jq RUN apk add --no-cache jq
COPY entrypoint.sh /entrypoint.sh COPY entrypoint-l2.sh /entrypoint.sh
VOLUME ["/db"] VOLUME ["/db"]
......
#!/bin/sh
set -exu
VERBOSITY=${GETH_VERBOSITY:-3}
GETH_DATA_DIR=/db
GETH_CHAINDATA_DIR="$GETH_DATA_DIR/geth/chaindata"
GENESIS_FILE_PATH="${GENESIS_FILE_PATH:-/genesis.json}"
CHAIN_ID=$(cat "$GENESIS_FILE_PATH" | jq -r .config.chainId)
RPC_PORT="${RPC_PORT:-8545}"
WS_PORT="${WS_PORT:-8546}"
if [ ! -d "$GETH_CHAINDATA_DIR" ]; then
echo "$GETH_CHAINDATA_DIR missing, running init"
echo "Initializing genesis."
geth --verbosity="$VERBOSITY" init \
--datadir="$GETH_DATA_DIR" \
"$GENESIS_FILE_PATH"
else
echo "$GETH_CHAINDATA_DIR exists."
fi
# Warning: Archive mode is required, otherwise old trie nodes will be
# pruned within minutes of starting the devnet.
exec geth \
--datadir="$GETH_DATA_DIR" \
--verbosity="$VERBOSITY" \
--http \
--http.corsdomain="*" \
--http.vhosts="*" \
--http.addr=0.0.0.0 \
--http.port="$RPC_PORT" \
--http.api=web3,debug,eth,txpool,net,engine \
--ws \
--ws.addr=0.0.0.0 \
--ws.port="$WS_PORT" \
--ws.origins="*" \
--ws.api=debug,eth,txpool,net,engine \
--syncmode=full \
--nodiscover \
--maxpeers=0 \
--networkid=$CHAIN_ID \
--authrpc.addr="0.0.0.0" \
--authrpc.port="8551" \
--authrpc.vhosts="*" \
--authrpc.jwtsecret=/config/jwt-secret.txt \
--gcmode=archive \
--metrics \
--metrics.addr=0.0.0.0 \
--metrics.port=6060 \
"$@"
...@@ -3,6 +3,7 @@ import os ...@@ -3,6 +3,7 @@ import os
import re import re
import subprocess import subprocess
import sys import sys
import json
from github import Github from github import Github
...@@ -13,9 +14,11 @@ REBUILD_ALL_PATTERNS = [ ...@@ -13,9 +14,11 @@ REBUILD_ALL_PATTERNS = [
r'ops/check-changed/.*', r'ops/check-changed/.*',
r'^go\.mod', r'^go\.mod',
r'^go\.sum', r'^go\.sum',
r'^pnpm-lock\.yaml',
r'ops/check-changed/.*' r'ops/check-changed/.*'
] ]
with open("../../nx.json") as file:
nx_json_data = json.load(file)
REBUILD_ALL_PATTERNS += nx_json_data["implicitDependencies"].keys()
WHITELISTED_BRANCHES = { WHITELISTED_BRANCHES = {
'master', 'master',
......
...@@ -6,10 +6,10 @@ WORKDIR /opt ...@@ -6,10 +6,10 @@ WORKDIR /opt
ENV DEBIAN_FRONTEND=noninteractive ENV DEBIAN_FRONTEND=noninteractive
RUN apt-get update && \ RUN apt-get update && \
apt-get install -y curl build-essential git && \ apt-get install -y curl build-essential git && \
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh && \ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup.sh && \
chmod +x ./rustup.sh && \ chmod +x ./rustup.sh && \
./rustup.sh -y ./rustup.sh -y
COPY ./.foundryrc ./.foundryrc COPY ./.foundryrc ./.foundryrc
...@@ -21,10 +21,10 @@ RUN git clone https://github.com/foundry-rs/foundry.git ./foundry \ ...@@ -21,10 +21,10 @@ RUN git clone https://github.com/foundry-rs/foundry.git ./foundry \
WORKDIR /opt/foundry WORKDIR /opt/foundry
RUN source $HOME/.profile && \ RUN source $HOME/.profile && \
cargo build --release && \ cargo build --release && \
strip /opt/foundry/target/release/forge && \ strip /opt/foundry/target/release/forge && \
strip /opt/foundry/target/release/cast && \ strip /opt/foundry/target/release/cast && \
strip /opt/foundry/target/release/anvil strip /opt/foundry/target/release/anvil
FROM ethereum/client-go:alltools-v1.10.25 as geth FROM ethereum/client-go:alltools-v1.10.25 as geth
...@@ -56,7 +56,9 @@ RUN apt-get update && \ ...@@ -56,7 +56,9 @@ RUN apt-get update && \
curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.48.0 && \ curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -b $(go env GOPATH)/bin v1.48.0 && \
curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh | bash curl -fLSs https://raw.githubusercontent.com/CircleCI-Public/circleci-cli/master/install.sh | bash
RUN echo "downloading pnpm" && npm i -g pnpm # We need to isntall yarn because a bespoke dependency installed from github https://codeload.github.com/Saw-mon-and-Natalie/clones-with-immutable-arg needs it
# it is installed from github which means it's postpack script which uses yarn is ran when unpacked into node_modules
RUN echo "downloading pnpm and yarn" && npm i -g pnpm && npm i -g yarn@1 && pnpm --version && yarn --version
RUN echo "downloading solidity compilers" && \ RUN echo "downloading solidity compilers" && \
curl -o solc-linux-amd64-v0.5.17+commit.d19bba13 -sL https://binaries.soliditylang.org/linux-amd64/solc-linux-amd64-v0.5.17+commit.d19bba13 && \ curl -o solc-linux-amd64-v0.5.17+commit.d19bba13 -sL https://binaries.soliditylang.org/linux-amd64/solc-linux-amd64-v0.5.17+commit.d19bba13 && \
...@@ -105,3 +107,8 @@ RUN echo "downloading mockery tool" && \ ...@@ -105,3 +107,8 @@ RUN echo "downloading mockery tool" && \
cp mockery-tmp-dir/mockery /usr/local/bin/mockery && \ cp mockery-tmp-dir/mockery /usr/local/bin/mockery && \
chmod +x /usr/local/bin/mockery && \ chmod +x /usr/local/bin/mockery && \
rm -rf mockery-tmp-dir rm -rf mockery-tmp-dir
RUN echo "installing mips binutils" && \
apt-get install -y binutils-mips-linux-gnu python3 python3-pip && \
pip3 install capstone pyelftools
...@@ -7,7 +7,7 @@ import { ...@@ -7,7 +7,7 @@ import {
} from '@eth-optimism/common-ts' } from '@eth-optimism/common-ts'
import { Provider } from '@ethersproject/abstract-provider' import { Provider } from '@ethersproject/abstract-provider'
import { ethers } from 'ethers' import { ethers } from 'ethers'
import * as DrippieArtifact from '@eth-optimism/contracts-periphery/artifacts/contracts/universal/drippie/Drippie.sol/Drippie.json' import * as DrippieArtifact from '@eth-optimism/contracts-bedrock/forge-artifacts/Drippie.sol/Drippie.json'
import { version } from '../../package.json' import { version } from '../../package.json'
......
AdminFaucetAuthModuleTest:test_adminProof_verify_succeeds() (gas: 57577)
AdminFaucetAuthModuleTest:test_nonAdminProof_verify_succeeds() (gas: 59050)
AdminFaucetAuthModuleTest:test_proofWithWrongId_verify_succeeds() (gas: 60673)
AssetReceiverTest:test_constructor_succeeds() (gas: 9696)
AssetReceiverTest:test_receive_succeeds() (gas: 20844)
AssetReceiverTest:test_withdrawERC20_succeeds() (gas: 183383)
AssetReceiverTest:test_withdrawERC20_unauthorized_reverts() (gas: 153517)
AssetReceiverTest:test_withdrawERC20withAmount_succeeds() (gas: 182567)
AssetReceiverTest:test_withdrawERC20withAmount_unauthorized_reverts() (gas: 153528)
AssetReceiverTest:test_withdrawERC721_succeeds() (gas: 50755)
AssetReceiverTest:test_withdrawERC721_unauthorized_reverts() (gas: 51063)
AssetReceiverTest:test_withdrawETH_succeeds() (gas: 28344)
AssetReceiverTest:test_withdrawETH_unauthorized_reverts() (gas: 10680)
AssetReceiverTest:test_withdrawETHwithAmount_succeeds() (gas: 28241)
AssetReceiverTest:test_withdrawETHwithAmount_unauthorized_reverts() (gas: 10738)
AttestationStationTest:test_attest_bulk_succeeds() (gas: 703749)
AttestationStationTest:test_attest_individual_succeeds() (gas: 632087)
AttestationStationTest:test_attest_single_succeeds() (gas: 651325)
Bytes_slice_Test:test_slice_acrossMultipleWords_works() (gas: 9413) Bytes_slice_Test:test_slice_acrossMultipleWords_works() (gas: 9413)
Bytes_slice_Test:test_slice_acrossWords_works() (gas: 1430) Bytes_slice_Test:test_slice_acrossWords_works() (gas: 1430)
Bytes_slice_Test:test_slice_fromNonZeroIdx_works() (gas: 17240) Bytes_slice_Test:test_slice_fromNonZeroIdx_works() (gas: 17240)
...@@ -32,12 +50,49 @@ DisputeGameFactory_SetImplementation_Test:test_setImplementation_notOwner_revert ...@@ -32,12 +50,49 @@ DisputeGameFactory_SetImplementation_Test:test_setImplementation_notOwner_revert
DisputeGameFactory_SetImplementation_Test:test_setImplementation_succeeds() (gas: 44243) DisputeGameFactory_SetImplementation_Test:test_setImplementation_succeeds() (gas: 44243)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_notOwner_reverts() (gas: 15950) DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_notOwner_reverts() (gas: 15950)
DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_succeeds() (gas: 18642) DisputeGameFactory_TransferOwnership_Test:test_transferOwnership_succeeds() (gas: 18642)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 491839) Drippie_Test:test_create_calledTwice_reverts() (gas: 168931)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 495751) Drippie_Test:test_create_succeeds() (gas: 183380)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 495049) Drippie_Test:test_drip_amount_succeeds() (gas: 285294)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 490600) Drippie_Test:test_drip_notExist_reverts() (gas: 14876)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 494512) Drippie_Test:test_drip_reentrant_reverts() (gas: 18853)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 493810) Drippie_Test:test_name_notExist_reverts() (gas: 16012)
Drippie_Test:test_notReentrant_zeroInterval_reverts() (gas: 18845)
Drippie_Test:test_not_active_reverts() (gas: 171074)
Drippie_Test:test_reentrant_succeeds() (gas: 180159)
Drippie_Test:test_set_statusNone_reverts() (gas: 168743)
Drippie_Test:test_set_statusSame_reverts() (gas: 169129)
Drippie_Test:test_set_status_succeeds() (gas: 198449)
Drippie_Test:test_shouldArchive_ifPaused_succeeds() (gas: 177260)
Drippie_Test:test_shouldNotAllowActive_ifArchived_reverts() (gas: 174581)
Drippie_Test:test_shouldNotAllowPaused_ifArchived_reverts() (gas: 174604)
Drippie_Test:test_shouldNotArchive_ifActive_reverts() (gas: 175622)
Drippie_Test:test_status_unauthorized_reverts() (gas: 167344)
Drippie_Test:test_trigger_oneFunction_succeeds() (gas: 338143)
Drippie_Test:test_trigger_twoFunctions_succeeds() (gas: 491870)
Drippie_Test:test_twice_inOneInterval_reverts() (gas: 303767)
FaucetTest:test_authAdmin_drip_succeeds() (gas: 366111)
FaucetTest:test_drip_afterTimeout_succeeds() (gas: 447899)
FaucetTest:test_drip_beforeTimeout_reverts() (gas: 378888)
FaucetTest:test_drip_disabledModule_reverts() (gas: 352405)
FaucetTest:test_drip_emitsEvent_succeeds() (gas: 369165)
FaucetTest:test_drip_githubSendsCorrectAmount_succeeds() (gas: 366611)
FaucetTest:test_drip_optimistNftSendsCorrectAmount_succeeds() (gas: 366555)
FaucetTest:test_drip_preventsReplayAttacks_succeeds() (gas: 369218)
FaucetTest:test_initialize_succeeds() (gas: 7626)
FaucetTest:test_nonAdmin_drip_fails() (gas: 262520)
FaucetTest:test_receive_succeeds() (gas: 17401)
FaucetTest:test_withdraw_nonAdmin_reverts() (gas: 13145)
FaucetTest:test_withdraw_succeeds() (gas: 78359)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 498900)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 503381)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 502679)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 505608)
FaultDisputeGame_ResolvesCorrectly_CorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 504939)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot1:test_resolvesCorrectly_succeeds() (gas: 497692)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2:test_resolvesCorrectly_succeeds() (gas: 502173)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3:test_resolvesCorrectly_succeeds() (gas: 501471)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot4:test_resolvesCorrectly_succeeds() (gas: 502373)
FaultDisputeGame_ResolvesCorrectly_IncorrectRoot5:test_resolvesCorrectly_succeeds() (gas: 501731)
FaultDisputeGame_Test:test_extraData_succeeds() (gas: 17426) FaultDisputeGame_Test:test_extraData_succeeds() (gas: 17426)
FaultDisputeGame_Test:test_gameData_succeeds() (gas: 17917) FaultDisputeGame_Test:test_gameData_succeeds() (gas: 17917)
FaultDisputeGame_Test:test_gameStart_succeeds() (gas: 10315) FaultDisputeGame_Test:test_gameStart_succeeds() (gas: 10315)
...@@ -331,6 +386,56 @@ OptimismPortal_Test:test_receive_succeeds() (gas: 127513) ...@@ -331,6 +386,56 @@ OptimismPortal_Test:test_receive_succeeds() (gas: 127513)
OptimismPortal_Test:test_simple_isOutputFinalized_succeeds() (gas: 32971) OptimismPortal_Test:test_simple_isOutputFinalized_succeeds() (gas: 32971)
OptimismPortal_Test:test_unpause_onlyGuardian_reverts() (gas: 46098) OptimismPortal_Test:test_unpause_onlyGuardian_reverts() (gas: 46098)
OptimismPortal_Test:test_unpause_succeeds() (gas: 31756) OptimismPortal_Test:test_unpause_succeeds() (gas: 31756)
OptimistAllowlistTest:test_constructor_succeeds() (gas: 20476)
OptimistAllowlistTest:test_isAllowedToMint_fromAllowlistAttestorWithFalsyValue_fails() (gas: 49842)
OptimistAllowlistTest:test_isAllowedToMint_fromAllowlistAttestor_succeeds() (gas: 49304)
OptimistAllowlistTest:test_isAllowedToMint_fromCoinbaseQuestAttestorWithFalsyValue_fails() (gas: 49544)
OptimistAllowlistTest:test_isAllowedToMint_fromCoinbaseQuestAttestor_succeeds() (gas: 53534)
OptimistAllowlistTest:test_isAllowedToMint_fromInvite_succeeds() (gas: 235508)
OptimistAllowlistTest:test_isAllowedToMint_fromWrongAllowlistAttestor_fails() (gas: 58311)
OptimistAllowlistTest:test_isAllowedToMint_fromWrongCoinbaseQuestAttestor_fails() (gas: 58268)
OptimistAllowlistTest:test_isAllowedToMint_fromWrongOptimistInviter_fails() (gas: 57601)
OptimistAllowlistTest:test_isAllowedToMint_withMultipleAttestations_succeeds() (gas: 324909)
OptimistAllowlistTest:test_isAllowedToMint_withoutAnyAttestations_fails() (gas: 23210)
OptimistInviterTest:test_claimInvite_claimBeforeMinCommitmentPeriod_reverts() (gas: 142819)
OptimistInviterTest:test_claimInvite_claimForSomeoneElse_succeeds() (gas: 245467)
OptimistInviterTest:test_claimInvite_replayingUsedNonce_reverts() (gas: 288437)
OptimistInviterTest:test_claimInvite_succeeds() (gas: 241374)
OptimistInviterTest:test_claimInvite_usingERC1271Wallet_succeeds() (gas: 245742)
OptimistInviterTest:test_claimInvite_usingSignatureIssuedForDifferentChain_reverts() (gas: 156587)
OptimistInviterTest:test_claimInvite_usingSignatureIssuedForDifferentContract_reverts() (gas: 156478)
OptimistInviterTest:test_claimInvite_usingSignatureIssuedForDifferentVersion_reverts() (gas: 155102)
OptimistInviterTest:test_claimInvite_whenIssuerHasNoInvitesLeft_reverts() (gas: 562110)
OptimistInviterTest:test_claimInvite_whenIssuerNeverReceivedInvites_reverts() (gas: 110711)
OptimistInviterTest:test_claimInvite_withIncorrectSignature_reverts() (gas: 253095)
OptimistInviterTest:test_claimInvite_withoutCommittingHash_reverts() (gas: 119210)
OptimistInviterTest:test_commitInvite_committingForSomeoneElse_succeeds() (gas: 140584)
OptimistInviterTest:test_commitInvite_committingForYourself_succeeds() (gas: 138628)
OptimistInviterTest:test_commitInvite_committingSameHashTwice_reverts() (gas: 142056)
OptimistInviterTest:test_grantInvites_adminAddingInvites_succeeds() (gas: 190757)
OptimistInviterTest:test_grantInvites_nonAdminAddingInvites_reverts() (gas: 14026)
OptimistInviterTest:test_initialize_succeeds() (gas: 14724)
OptimistTest:test_approve_soulbound_reverts() (gas: 70487)
OptimistTest:test_baseURI_returnsCorrectBaseURI_succeeds() (gas: 124568)
OptimistTest:test_burn_byNonOwner_reverts() (gas: 73197)
OptimistTest:test_burn_byOwner_succeeds() (gas: 54487)
OptimistTest:test_initialize_succeeds() (gas: 24977)
OptimistTest:test_mint_afterAllowlistAttestation_succeeds() (gas: 121465)
OptimistTest:test_mint_afterCoinbaseQuestAttestation_succeeds() (gas: 130362)
OptimistTest:test_mint_afterInviteClaimed_succeeds() (gas: 311331)
OptimistTest:test_mint_afterMultipleAttestations_succeeds() (gas: 377762)
OptimistTest:test_mint_forAlreadyMintedClaimer_reverts() (gas: 118023)
OptimistTest:test_mint_forNonAllowlistedClaimer_reverts() (gas: 29886)
OptimistTest:test_mint_secondaryMinter_succeeds() (gas: 72711)
OptimistTest:test_multicall_batchingClaimAndMint_succeeds() (gas: 308376)
OptimistTest:test_setApprovalForAll_soulbound_reverts() (gas: 74239)
OptimistTest:test_supportsInterface_returnsCorrectInterfaceForERC721_succeeds() (gas: 5805)
OptimistTest:test_tokenIdOfAddress_returnsOwnerID_succeeds() (gas: 63730)
OptimistTest:test_tokenURI_returnsCorrectTokenURI_succeeds() (gas: 195908)
OptimistTest:test_transferFrom_soulbound_reverts() (gas: 75512)
PreimageOracle_Test:test_computePreimageKey_succeeds() (gas: 6267)
PreimageOracle_Test:test_loadKeccak256PreimagePart_outOfBoundsOffset_reverts() (gas: 9025)
PreimageOracle_Test:test_loadKeccak256PreimagePart_succeeds() (gas: 77552)
ProxyAdmin_Test:test_chugsplashChangeProxyAdmin_succeeds() (gas: 35586) ProxyAdmin_Test:test_chugsplashChangeProxyAdmin_succeeds() (gas: 35586)
ProxyAdmin_Test:test_chugsplashGetProxyAdmin_succeeds() (gas: 15675) ProxyAdmin_Test:test_chugsplashGetProxyAdmin_succeeds() (gas: 15675)
ProxyAdmin_Test:test_chugsplashGetProxyImplementation_succeeds() (gas: 51084) ProxyAdmin_Test:test_chugsplashGetProxyImplementation_succeeds() (gas: 51084)
...@@ -460,5 +565,10 @@ SystemConfig_Setters_TestFail:test_setResourceConfig_lowGasLimit_reverts() (gas: ...@@ -460,5 +565,10 @@ SystemConfig_Setters_TestFail:test_setResourceConfig_lowGasLimit_reverts() (gas:
SystemConfig_Setters_TestFail:test_setResourceConfig_notOwner_reverts() (gas: 11790) SystemConfig_Setters_TestFail:test_setResourceConfig_notOwner_reverts() (gas: 11790)
SystemConfig_Setters_TestFail:test_setResourceConfig_zeroDenominator_reverts() (gas: 13039) SystemConfig_Setters_TestFail:test_setResourceConfig_zeroDenominator_reverts() (gas: 13039)
SystemConfig_Setters_TestFail:test_setUnsafeBlockSigner_notOwner_reverts() (gas: 10616) SystemConfig_Setters_TestFail:test_setUnsafeBlockSigner_notOwner_reverts() (gas: 10616)
TransactorTest:test_call_succeeds() (gas: 26709)
TransactorTest:test_call_unauthorized_reverts() (gas: 16543)
TransactorTest:test_constructor_succeeds() (gas: 9739)
TransactorTest:test_delegateCall_succeeds() (gas: 20909)
TransactorTest:test_delegateCall_unauthorized_reverts() (gas: 16550)
TransferOnionTest:test_constructor_succeeds() (gas: 564855) TransferOnionTest:test_constructor_succeeds() (gas: 564855)
TransferOnionTest:test_unwrap_succeeds() (gas: 724955) TransferOnionTest:test_unwrap_succeeds() (gas: 724955)
\ No newline at end of file
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.7.6; pragma solidity 0.7.6;
interface IPreimageOracle { import { IPreimageOracle } from "./interfaces/IPreimageOracle.sol";
function readPreimage(bytes32 key, uint256 offset) external view returns (bytes32 dat, uint256 datLen);
} /// @title MIPS
/// @notice The MIPS contract emulates a single MIPS instruction.
/// Note that delay slots are isolated instructions:
/// the nextPC in the state pre-schedules where the VM jumps next.
/// The Step input is a packed VM state, with binary-merkle-tree
/// witness data for memory reads/writes.
/// The Step outputs a keccak256 hash of the packed VM State,
/// and logs the resulting state for offchain usage.
/// @dev https://inst.eecs.berkeley.edu/~cs61c/resources/MIPS_Green_Sheet.pdf
/// @dev https://www.cs.cmu.edu/afs/cs/academic/class/15740-f97/public/doc/mips-isa.pdf
/// (page A-177)
/// @dev https://uweb.engr.arizona.edu/~ece369/Resources/spim/MIPSReference.pdf
/// @dev https://en.wikibooks.org/wiki/MIPS_Assembly/Instruction_Formats
/// @dev https://github.com/golang/go/blob/master/src/syscall/zerrors_linux_mips.go
/// MIPS linux kernel errors used by Go runtime
contract MIPS {
// https://inst.eecs.berkeley.edu/~cs61c/resources/MIPS_Green_Sheet.pdf /// @notice Stores the VM state.
// https://uweb.engr.arizona.edu/~ece369/Resources/spim/MIPSReference.pdf /// Total state size: 32 + 32 + 6 * 4 + 1 + 1 + 8 + 32 * 4 = 226 bytes
// https://en.wikibooks.org/wiki/MIPS_Assembly/Instruction_Formats /// If nextPC != pc + 4, then the VM is executing a branch/jump delay slot.
struct State {
bytes32 memRoot;
bytes32 preimageKey;
uint32 preimageOffset;
uint32 pc;
uint32 nextPC;
uint32 lo;
uint32 hi;
uint32 heap;
uint8 exitCode;
bool exited;
uint64 step;
uint32[32] registers;
}
// https://www.cs.cmu.edu/afs/cs/academic/class/15740-f97/public/doc/mips-isa.pdf /// @notice Start of the data segment.
// page A-177 uint32 constant public BRK_START = 0x40000000;
uint32 constant FD_STDIN = 0;
uint32 constant FD_STDOUT = 1;
uint32 constant FD_STDERR = 2;
uint32 constant FD_HINT_READ = 3;
uint32 constant FD_HINT_WRITE = 4;
uint32 constant FD_PREIMAGE_READ = 5;
uint32 constant FD_PREIMAGE_WRITE = 6;
uint32 constant EBADF = 0x9;
uint32 constant EINVAL = 0x16;
/// @notice The pre-image oracle.
IPreimageOracle public oracle;
/// @notice Extends the value leftwards with its most significant bit (sign extension).
function SE(uint32 dat, uint32 idx) internal pure returns (uint32) {
bool isSigned = (dat >> (idx - 1)) != 0;
uint256 signed = ((1 << (32 - idx)) - 1) << idx;
uint256 mask = (1 << idx) - 1;
return uint32(dat & mask | (isSigned ? signed : 0));
}
// MIPS linux kernel errors used by Go runtime: /// @notice Computes the hash of the MIPS state.
// https://github.com/golang/go/blob/master/src/syscall/zerrors_linux_mips.go /// @return out_ The hash of the MIPS state.
function outputState() internal returns (bytes32 out_) {
assembly {
// copies 'size' bytes, right-aligned in word at 'from', to 'to', incl. trailing data
function copyMem(from, to, size) -> fromOut, toOut {
mstore(to, mload(add(from, sub(32, size))))
fromOut := add(from, 32)
toOut := add(to, size)
}
// From points to the MIPS State
let from := 0x80
// Copy to the free memory pointer
let start := mload(0x40)
let to := start
// Copy state to free memory
from, to := copyMem(from, to, 32) // memRoot
from, to := copyMem(from, to, 32) // preimageKey
from, to := copyMem(from, to, 4) // preimageOffset
from, to := copyMem(from, to, 4) // pc
from, to := copyMem(from, to, 4) // nextPC
from, to := copyMem(from, to, 4) // lo
from, to := copyMem(from, to, 4) // hi
from, to := copyMem(from, to, 4) // heap
from, to := copyMem(from, to, 1) // exitCode
from, to := copyMem(from, to, 1) // exited
from, to := copyMem(from, to, 8) // step
from := add(from, 32) // offset to registers
// Copy registers
for { let i := 0 } lt(i, 32) { i := add(i, 1) } {
from, to := copyMem(from, to, 4)
}
// Clean up end of memory
mstore(to, 0)
// Log the resulting MIPS state, for debugging
log0(start, sub(to, start))
// Compute the hash of the resulting MIPS state
out_ := keccak256(start, sub(to, start))
}
return out_;
}
// This MIPS contract emulates a single MIPS instruction. /// @notice Handles a syscall.
// function handleSyscall() internal returns (bytes32) {
// Note that delay slots are isolated instructions: // Load state from memory
// the nextPC in the state pre-schedules where the VM jumps next. State memory state;
// assembly {
// The Step input is a packed VM state, with binary-merkle-tree witness data for memory reads/writes. state := 0x80
// The Step outputs a keccak256 hash of the packed VM State, and logs the resulting state for offchain usage. }
contract MIPS {
struct State { uint32 syscall_no = state.registers[2];
bytes32 memRoot; uint32 v0 = 0;
bytes32 preimageKey; uint32 v1 = 0;
uint32 preimageOffset;
uint32 pc; uint32 a0 = state.registers[4];
uint32 nextPC; // State is executing a branch/jump delay slot if nextPC != pc+4 uint32 a1 = state.registers[5];
uint32 lo; uint32 a2 = state.registers[6];
uint32 hi;
uint32 heap; if (syscall_no == 4090) {
uint8 exitCode; // mmap
bool exited; uint32 sz = a1;
uint64 step; if (sz&4095 != 0) { // adjust size to align with page size
uint32[32] registers; sz += 4096 - (sz&4095);
} }
if (a0 == 0) {
// total State size: 32+32+6*4+1+1+8+32*4 = 226 bytes v0 = state.heap;
state.heap += sz;
uint32 constant public BRK_START = 0x40000000; } else {
v0 = a0;
uint32 constant FD_STDIN = 0; }
uint32 constant FD_STDOUT = 1; } else if (syscall_no == 4045) {
uint32 constant FD_STDERR = 2; // brk
uint32 constant FD_HINT_READ = 3; v0 = BRK_START;
uint32 constant FD_HINT_WRITE = 4; } else if (syscall_no == 4120) {
uint32 constant FD_PREIMAGE_READ = 5; // clone (not supported)
uint32 constant FD_PREIMAGE_WRITE = 6; v0 = 1;
} else if (syscall_no == 4246) {
uint32 constant EBADF = 0x9; // exit group
uint32 constant EINVAL = 0x16; state.exited = true;
state.exitCode = uint8(a0);
IPreimageOracle public oracle; return outputState();
} else if (syscall_no == 4003) { // read
function SE(uint32 dat, uint32 idx) internal pure returns (uint32) { // args: a0 = fd, a1 = addr, a2 = count
bool isSigned = (dat >> (idx-1)) != 0; // returns: v0 = read, v1 = err code
uint256 signed = ((1 << (32-idx)) - 1) << idx; if (a0 == FD_STDIN) {
uint256 mask = (1 << idx) - 1; // leave v0 and v1 zero: read nothing, no error
return uint32(dat&mask | (isSigned ? signed : 0)); } else if (a0 == FD_PREIMAGE_READ) { // pre-image oracle
} // verify proof 1 is correct, and get the existing memory.
uint32 mem = readMem(a1 & 0xFFffFFfc, 1); // mask the addr to align it to 4 bytes
function outputState() internal returns (bytes32 out) { (bytes32 dat, uint256 datLen) = oracle.readPreimage(state.preimageKey, state.preimageOffset);
assembly { assembly { // assembly for more precise ops, and no var count limit
// copies 'size' bytes, right-aligned in word at 'from', to 'to', incl. trailing data let alignment := and(a1, 3) // the read might not start at an aligned address
function copyMem(from, to, size) -> fromOut, toOut { let space := sub(4, alignment) // remaining space in memory word
mstore(to, mload(add(from, sub(32, size)))) if lt(space, datLen) { datLen := space } // if less space than data, shorten data
fromOut := add(from, 32) if lt(a2, datLen) { datLen := a2 } // if requested to read less, read less
toOut := add(to, size) dat := shr(sub(256, mul(datLen, 8)), dat) // right-align data
} dat := shl(mul(sub(sub(4, datLen), alignment), 8), dat) // position data to insert into memory word
let from := 0x80 // state let mask := sub(shl(mul(sub(4, alignment), 8), 1), 1) // mask all bytes after start
let start := mload(0x40) // free mem ptr let suffixMask := sub(shl(mul(sub(sub(4, alignment), datLen), 8), 1), 1) // mask of all bytes starting from end, maybe none
let to := start mask := and(mask, not(suffixMask)) // reduce mask to just cover the data we insert
from, to := copyMem(from, to, 32) // memRoot mem := or(and(mem, not(mask)), dat) // clear masked part of original memory, and insert data
from, to := copyMem(from, to, 32) // preimageKey }
from, to := copyMem(from, to, 4) // preimageOffset writeMem(a1 & 0xFFffFFfc, 1, mem);
from, to := copyMem(from, to, 4) // pc state.preimageOffset += uint32(datLen);
from, to := copyMem(from, to, 4) // nextPC v0 = uint32(datLen);
from, to := copyMem(from, to, 4) // lo } else if (a0 == FD_HINT_READ) { // hint response
from, to := copyMem(from, to, 4) // hi // don't actually read into memory, just say we read it all, we ignore the result anyway
from, to := copyMem(from, to, 4) // heap v0 = a2;
from, to := copyMem(from, to, 1) // exitCode } else {
from, to := copyMem(from, to, 1) // exited v0 = 0xFFffFFff;
from, to := copyMem(from, to, 8) // step v1 = EBADF;
from := add(from, 32) // offset to registers }
for { let i := 0 } lt(i, 32) { i := add(i, 1) } { from, to := copyMem(from, to, 4) } // registers } else if (syscall_no == 4004) { // write
mstore(to, 0) // clean up end // args: a0 = fd, a1 = addr, a2 = count
log0(start, sub(to, start)) // log the resulting MIPS state, for debugging // returns: v0 = written, v1 = err code
out := keccak256(start, sub(to, start)) if (a0 == FD_STDOUT || a0 == FD_STDERR || a0 == FD_HINT_WRITE) {
} v0 = a2; // tell program we have written everything
return out; } else if (a0 == FD_PREIMAGE_WRITE) { // pre-image oracle
} uint32 mem = readMem(a1 & 0xFFffFFfc, 1); // mask the addr to align it to 4 bytes
bytes32 key = state.preimageKey;
assembly { // assembly for more precise ops, and no var count limit
let alignment := and(a1, 3) // the read might not start at an aligned address
let space := sub(4, alignment) // remaining space in memory word
if lt(space, a2) { a2 := space } // if less space than data, shorten data
key := shl(mul(a2, 8), key) // shift key, make space for new info
let mask := sub(shl(mul(a2, 8), 1), 1) // mask for extracting value from memory
mem := and(shr(mul(sub(space, a2), 8), mem), mask) // align value to right, mask it
key := or(key, mem) // insert into key
}
state.preimageKey = key;
state.preimageOffset = 0; // reset offset, to read new pre-image data from the start
v0 = a2;
} else {
v0 = 0xFFffFFff;
v1 = EBADF;
}
} else if (syscall_no == 4055) { // fcntl
// args: a0 = fd, a1 = cmd
if (a1 == 3) { // F_GETFL: get file descriptor flags
if (a0 == FD_STDIN || a0 == FD_PREIMAGE_READ || a0 == FD_HINT_READ) {
v0 = 0; // O_RDONLY
} else if (a0 == FD_STDOUT || a0 == FD_STDERR || a0 == FD_PREIMAGE_WRITE || a0 == FD_HINT_WRITE) {
v0 = 1; // O_WRONLY
} else {
v0 = 0xFFffFFff;
v1 = EBADF;
}
} else {
v0 = 0xFFffFFff;
v1 = EINVAL; // cmd not recognized by this kernel
}
}
state.registers[2] = v0;
state.registers[7] = v1;
function handleSyscall() internal returns (bytes32) { state.pc = state.nextPC;
State memory state; state.nextPC = state.nextPC + 4;
assembly {
state := 0x80 return outputState();
} }
uint32 syscall_no = state.registers[2];
uint32 v0 = 0; /// @notice Handles a branch instruction, updating the MIPS state PC where needed.
uint32 v1 = 0; /// @param _opcode The opcode of the branch instruction.
/// @param _insn The instruction to be executed.
uint32 a0 = state.registers[4]; /// @param _rtReg The register to be used for the branch.
uint32 a1 = state.registers[5]; /// @param _rs The register to be compared with the branch register.
uint32 a2 = state.registers[6]; /// @return out_ The hashed MIPS state.
function handleBranch(uint32 _opcode, uint32 _insn, uint32 _rtReg, uint32 _rs) internal returns (bytes32 out_) {
if (syscall_no == 4090) { // Load state from memory
// mmap State memory state;
uint32 sz = a1; assembly {
if (sz&4095 != 0) { // adjust size to align with page size state := 0x80
sz += 4096 - (sz&4095); }
}
if (a0 == 0) { bool shouldBranch = false;
v0 = state.heap;
state.heap += sz; // beq/bne: Branch on equal / not equal
} else { if (_opcode == 4 || _opcode == 5) {
v0 = a0; uint32 rt = state.registers[_rtReg];
} shouldBranch = (_rs == rt && _opcode == 4) || (_rs != rt && _opcode == 5);
} else if (syscall_no == 4045) { }
// brk // blez: Branches if instruction is less than or equal to zero
v0 = BRK_START; else if (_opcode == 6) {
} else if (syscall_no == 4120) { shouldBranch = int32(_rs) <= 0;
// clone (not supported) }
v0 = 1; // bgtz: Branches if instruction is greater than zero
} else if (syscall_no == 4246) { else if (_opcode == 7) {
// exit group shouldBranch = int32(_rs) > 0;
state.exited = true; }
state.exitCode = uint8(a0); // bltz/bgez: Branch on less than zero / greater than or equal to zero
return outputState(); else if (_opcode == 1) {
} else if (syscall_no == 4003) { // read // regimm
// args: a0 = fd, a1 = addr, a2 = count uint32 rtv = ((_insn >> 16) & 0x1F);
// returns: v0 = read, v1 = err code if (rtv == 0) {
if (a0 == FD_STDIN) { shouldBranch = int32(_rs) < 0;
// leave v0 and v1 zero: read nothing, no error }
} else if (a0 == FD_PREIMAGE_READ) { // pre-image oracle if (rtv == 1) {
// verify proof 1 is correct, and get the existing memory. shouldBranch = int32(_rs) >= 0;
uint32 mem = readMem(a1 & 0xFFffFFfc, 1); // mask the addr to align it to 4 bytes }
(bytes32 dat, uint256 datLen) = oracle.readPreimage(state.preimageKey, state.preimageOffset); }
assembly { // assembly for more precise ops, and no var count limit
let alignment := and(a1, 3) // the read might not start at an aligned address // Update the state's previous PC
let space := sub(4, alignment) // remaining space in memory word uint32 prevPC = state.pc;
if lt(space, datLen) { datLen := space } // if less space than data, shorten data
if lt(a2, datLen) { datLen := a2 } // if requested to read less, read less // Execute the delay slot first
dat := shr(sub(256, mul(datLen, 8)), dat) // right-align data state.pc = state.nextPC;
dat := shl(mul(add(sub(4, datLen), alignment), 8), dat) // position data to insert into memory word
let mask := sub(shl(mul(sub(4, alignment), 8), 1), 1) // mask all bytes after start // If we should branch, update the PC to the branch target
let suffixMask := sub(shl(mul(sub(sub(4, alignment), datLen), 8), 1), 1) // mask of all bytes starting from end, maybe none // Otherwise, proceed to the next instruction
mask := and(mask, not(suffixMask)) // reduce mask to just cover the data we insert if (shouldBranch) {
mem := or(and(mem, not(mask)), dat) // clear masked part of original memory, and insert data state.nextPC = prevPC + 4 + (SE(_insn & 0xFFFF, 16) << 2);
}
writeMem(a1 & 0xFFffFFfc, 1, mem);
state.preimageOffset += uint32(datLen);
v0 = uint32(datLen);
} else if (a0 == FD_HINT_READ) { // hint response
// don't actually read into memory, just say we read it all, we ignore the result anyway
v0 = a2;
} else {
v0 = 0xFFffFFff;
v1 = EBADF;
}
} else if (syscall_no == 4004) { // write
// args: a0 = fd, a1 = addr, a2 = count
// returns: v0 = written, v1 = err code
if (a0 == FD_STDOUT || a0 == FD_STDERR || a0 == FD_HINT_WRITE) {
v0 = a2; // tell program we have written everything
} else if (a0 == FD_PREIMAGE_WRITE) { // pre-image oracle
uint32 mem = readMem(a1 & 0xFFffFFfc, 1); // mask the addr to align it to 4 bytes
bytes32 key = state.preimageKey;
assembly { // assembly for more precise ops, and no var count limit
let alignment := and(a1, 3) // the read might not start at an aligned address
let space := sub(4, alignment) // remaining space in memory word
if lt(space, a2) { a2 := space } // if less space than data, shorten data
key := shl(mul(a2, 8), key) // shift key, make space for new info
let mask := sub(shl(mul(a2, 8), 1), 1) // mask for extracting value from memory
mem := and(shr(mul(sub(space, a2), 8), mem), mask) // align value to right, mask it
key := or(key, mem) // insert into key
}
state.preimageKey = key;
state.preimageOffset = 0; // reset offset, to read new pre-image data from the start
v0 = a2;
} else {
v0 = 0xFFffFFff;
v1 = EBADF;
}
} else if (syscall_no == 4055) { // fcntl
// args: a0 = fd, a1 = cmd
if (a1 == 3) { // F_GETFL: get file descriptor flags
if (a0 == FD_STDIN || a0 == FD_PREIMAGE_READ || a0 == FD_HINT_READ) {
v0 = 0; // O_RDONLY
} else if (a0 == FD_STDOUT || a0 == FD_STDERR || a0 == FD_PREIMAGE_WRITE || a0 == FD_HINT_WRITE) {
v0 = 1; // O_WRONLY
} else { } else {
v0 = 0xFFffFFff; state.nextPC = state.nextPC + 4;
v1 = EBADF;
} }
} else {
v0 = 0xFFffFFff; // Return the hash of the resulting state
v1 = EINVAL; // cmd not recognized by this kernel out_ = outputState();
}
} }
state.registers[2] = v0; /// @notice Handles HI and LO register instructions.
state.registers[7] = v1; /// @param _func The function code of the instruction.
/// @param _rs The value of the RS register.
/// @param _rt The value of the RT register.
/// @param _storeReg The register to store the result in.
/// @return out_ The hash of the resulting MIPS state.
function handleHiLo(uint32 _func, uint32 _rs, uint32 _rt, uint32 _storeReg) internal returns (bytes32 out_) {
// Load state from memory
State memory state;
assembly {
state := 0x80
}
uint32 val;
// mfhi: Move the contents of the HI register into the destination
if (_func == 0x10) {
val = state.hi;
}
// mthi: Move the contents of the source into the HI register
else if (_func == 0x11) {
state.hi = _rs;
}
// mflo: Move the contents of the LO register into the destination
else if (_func == 0x12) {
val = state.lo;
}
// mtlo: Move the contents of the source into the LO register
else if (_func == 0x13) {
state.lo = _rs;
}
// mult: Multiplies `rs` by `rt` and stores the result in HI and LO registers
else if (_func == 0x18) {
uint64 acc = uint64(int64(int32(_rs)) * int64(int32(_rt)));
state.hi = uint32(acc >> 32);
state.lo = uint32(acc);
}
// multu: Unsigned multiplies `rs` by `rt` and stores the result in HI and LO registers
else if (_func == 0x19) {
uint64 acc = uint64(uint64(_rs) * uint64(_rt));
state.hi = uint32(acc >> 32);
state.lo = uint32(acc);
}
// div: Divides `rs` by `rt`.
// Stores the quotient in LO
// And the remainder in HI
else if (_func == 0x1a) {
state.hi = uint32(int32(_rs) % int32(_rt));
state.lo = uint32(int32(_rs) / int32(_rt));
}
// divu: Unsigned divides `rs` by `rt`.
// Stores the quotient in LO
// And the remainder in HI
else if (_func == 0x1b) {
state.hi = _rs % _rt;
state.lo = _rs / _rt;
}
state.pc = state.nextPC; // Store the result in the destination register, if applicable
state.nextPC = state.nextPC + 4; if (_storeReg != 0) {
state.registers[_storeReg] = val;
}
return outputState(); // Update the PC
} state.pc = state.nextPC;
state.nextPC = state.nextPC + 4;
function handleBranch(uint32 opcode, uint32 insn, uint32 rtReg, uint32 rs) internal returns (bytes32) { // Return the hash of the resulting state
State memory state; out_ = outputState();
assembly {
state := 0x80
}
bool shouldBranch = false;
if (opcode == 4 || opcode == 5) { // beq/bne
uint32 rt = state.registers[rtReg];
shouldBranch = (rs == rt && opcode == 4) || (rs != rt && opcode == 5);
} else if (opcode == 6) { shouldBranch = int32(rs) <= 0; // blez
} else if (opcode == 7) { shouldBranch = int32(rs) > 0; // bgtz
} else if (opcode == 1) {
// regimm
uint32 rtv = ((insn >> 16) & 0x1F);
if (rtv == 0) shouldBranch = int32(rs) < 0; // bltz
if (rtv == 1) shouldBranch = int32(rs) >= 0; // bgez
} }
uint32 prevPC = state.pc; /// @notice Handles a jump instruction, updating the MIPS state PC where needed.
state.pc = state.nextPC; // execute the delay slot first /// @param _linkReg The register to store the link to the instruction after the delay slot instruction.
if (shouldBranch) { /// @param _dest The destination to jump to.
state.nextPC = prevPC + 4 + (SE(insn&0xFFFF, 16)<<2); // then continue with the instruction the branch jumps to. /// @return out_ The hashed MIPS state.
} else { function handleJump(uint32 _linkReg, uint32 _dest) internal returns (bytes32 out_) {
state.nextPC = state.nextPC + 4; // branch not taken // Load state from memory.
} State memory state;
assembly {
state := 0x80
}
return outputState(); // Update the next PC to the jump destination.
} uint32 prevPC = state.pc;
state.pc = state.nextPC;
state.nextPC = _dest;
function handleHiLo(uint32 func, uint32 rs, uint32 rt, uint32 storeReg) internal returns (bytes32) { // Update the link-register to the instruction after the delay slot instruction.
State memory state; if (_linkReg != 0) {
assembly { state.registers[_linkReg] = prevPC + 8;
state := 0x80 }
}
uint32 val;
if (func == 0x10) val = state.hi; // mfhi
else if (func == 0x11) state.hi = rs; // mthi
else if (func == 0x12) val = state.lo; // mflo
else if (func == 0x13) state.lo = rs; // mtlo
else if (func == 0x18) { // mult
uint64 acc = uint64(int64(int32(rs))*int64(int32(rt)));
state.hi = uint32(acc>>32);
state.lo = uint32(acc);
} else if (func == 0x19) { // multu
uint64 acc = uint64(uint64(rs)*uint64(rt));
state.hi = uint32(acc>>32);
state.lo = uint32(acc);
} else if (func == 0x1a) { // div
state.hi = uint32(int32(rs)%int32(rt));
state.lo = uint32(int32(rs)/int32(rt));
} else if (func == 0x1b) { // divu
state.hi = rs%rt;
state.lo = rs/rt;
}
if (storeReg != 0) { // Return the hash of the resulting state.
state.registers[storeReg] = val; out_ = outputState();
} }
state.pc = state.nextPC; /// @notice Handles a storing a value into a register.
state.nextPC = state.nextPC + 4; /// @param _storeReg The register to store the value into.
/// @param _val The value to store.
/// @param _conditional Whether or not the store is conditional.
/// @return out_ The hashed MIPS state.
function handleRd(uint32 _storeReg, uint32 _val, bool _conditional) internal returns (bytes32 out_) {
// Load state from memory.
State memory state;
assembly {
state := 0x80
}
return outputState(); // The destination register must be valid.
} require(_storeReg < 32, "valid register");
function handleJump(uint32 linkReg, uint32 dest) internal returns (bytes32) { // Never write to reg 0, and it can be conditional (movz, movn).
State memory state; if (_storeReg != 0 && _conditional) {
assembly { state.registers[_storeReg] = _val;
state := 0x80 }
}
uint32 prevPC = state.pc;
state.pc = state.nextPC;
state.nextPC = dest;
if (linkReg != 0) {
state.registers[linkReg] = prevPC+8; // set the link-register to the instr after the delay slot instruction.
}
return outputState();
}
function handleRd(uint32 storeReg, uint32 val, bool conditional) internal returns (bytes32) { // Update the PC.
State memory state; state.pc = state.nextPC;
assembly { state.nextPC = state.nextPC + 4;
state := 0x80
}
require(storeReg < 32, "valid register");
// never write to reg 0, and it can be conditional (movz, movn)
if (storeReg != 0 && conditional) {
state.registers[storeReg] = val;
}
state.pc = state.nextPC; // Return the hash of the resulting state.
state.nextPC = state.nextPC + 4; out_ = outputState();
return outputState();
}
function proofOffset(uint8 proofIndex) internal pure returns (uint256 offset) {
// A proof of 32 bit memory, with 32-byte leaf values, is (32-5)=27 bytes32 entries.
// And the leaf value itself needs to be encoded as well. And proof.offset == 358
offset = 358 + (uint256(proofIndex) * (28*32));
uint256 s = 0;
assembly { s := calldatasize() }
require(s >= (offset + 28*32), "check that there is enough calldata");
return offset;
}
function readMem(uint32 addr, uint8 proofIndex) internal pure returns (uint32 out) {
uint256 offset = proofOffset(proofIndex);
assembly {
if and(addr, 3) { revert(0, 0) } // quick addr alignment check
let leaf := calldataload(offset)
offset := add(offset, 32)
function hashPair(a, b) -> h {
mstore(0, a) // use scratch space slots to hash the two nodes together
mstore(32, b)
h := keccak256(0, 64)
}
let path := shr(5, addr)
let node := leaf // starting from the leaf node, work back up by combining with siblings, to reconstruct the root
for { let i := 0 } lt(i, 27) { i := add(i, 1) } {
let sibling := calldataload(offset)
offset := add(offset, 32)
switch and(shr(i, path), 1)
case 0 { node := hashPair(node, sibling) }
case 1 { node := hashPair(sibling, node) }
}
let memRoot := mload(0x80) // load memRoot, first field of state
if iszero(eq(node, memRoot)) { // verify the root matches
mstore(0, 0x0badf00d)
revert(0, 32)
}
// bits to shift = (32 - 4 - (addr % 32)) * 8
let shamt := shl(3, sub(sub(32, 4), and(addr, 31)))
out := and(shr(shamt, leaf), 0xFFffFFff)
} }
return out;
} /// @notice Computes the offset of the proof in the calldata.
/// @param _proofIndex The index of the proof in the calldata.
// writeMem writes the value by first overwriting the part of the leaf, and then recomputing the memory merkle root. /// @return offset_ The offset of the proof in the calldata.
function writeMem(uint32 addr, uint8 proofIndex, uint32 value) internal pure { function proofOffset(uint8 _proofIndex) internal pure returns (uint256 offset_) {
uint256 offset = proofOffset(proofIndex); // A proof of 32 bit memory, with 32-byte leaf values, is (32-5)=27 bytes32 entries.
assembly { // And the leaf value itself needs to be encoded as well. And proof.offset == 358
if and(addr, 3) { revert(0, 0) } // quick addr alignment check offset_ = 358 + (uint256(_proofIndex) * (28 * 32));
let leaf := calldataload(offset) uint256 s = 0;
let shamt := shl(3, sub(sub(32, 4), and(addr, 31))) assembly { s := calldatasize() }
// mask out 4 bytes, and OR in the value require(s >= (offset_ + 28 * 32), "check that there is enough calldata");
leaf := or(and(leaf, not(shl(shamt, 0xFFffFFff))), shl(shamt, value)) return offset_;
offset := add(offset, 32)
function hashPair(a, b) -> h {
mstore(0, a) // use scratch space slots to hash the two nodes together
mstore(32, b)
h := keccak256(0, 64)
}
let path := shr(5, addr)
let node := leaf // starting from the leaf node, work back up by combining with siblings, to reconstruct the root
for { let i := 0 } lt(i, 27) { i := add(i, 1) } {
let sibling := calldataload(offset)
offset := add(offset, 32)
switch and(shr(i, path), 1)
case 0 { node := hashPair(node, sibling) }
case 1 { node := hashPair(sibling, node) }
}
mstore(0x80, node) // store new memRoot, first field of state
} }
}
/// @notice Reads a 32-bit value from memory.
// will revert if any required input state is missing /// @param _addr The address to read from.
function step(bytes calldata stateData, bytes calldata proof) public returns (bytes32) { /// @param _proofIndex The index of the proof in the calldata.
State memory state; /// @return out_ The hashed MIPS state.
// packed data is ~6 times smaller function readMem(uint32 _addr, uint8 _proofIndex) internal pure returns (uint32 out_) {
assembly { // Compute the offset of the proof in the calldata.
if iszero(eq(state, 0x80)) { // expected state mem offset check uint256 offset = proofOffset(_proofIndex);
revert(0,0)
} assembly {
if iszero(eq(mload(0x40), mul(32, 48))) { // expected memory check // Validate the address alignement.
revert(0,0) if and(_addr, 3) {
} revert(0, 0)
if iszero(eq(stateData.offset, 100)) { // 32*3+4=100 expected state data offset }
revert(0,0)
} // Load the leaf value.
if iszero(eq(proof.offset, 358)) { // 100+32+226=358 expected proof offset let leaf := calldataload(offset)
revert(0,0) offset := add(offset, 32)
}
function putField(callOffset, memOffset, size) -> callOffsetOut, memOffsetOut { // Convenience function to hash two nodes together in scratch space.
// calldata is packed, thus starting left-aligned, shift-right to pad and right-align function hashPair(a, b) -> h {
let w := shr(shl(3, sub(32, size)), calldataload(callOffset)) mstore(0, a)
mstore(memOffset, w) mstore(32, b)
callOffsetOut := add(callOffset, size) h := keccak256(0, 64)
memOffsetOut := add(memOffset, 32) }
}
let c := stateData.offset // calldata offset // Start with the leaf node.
let m := 0x80 // mem offset // Work back up by combining with siblings, to reconstruct the root.
c, m := putField(c, m, 32) // memRoot let path := shr(5, _addr)
c, m := putField(c, m, 32) // preimageKey let node := leaf
c, m := putField(c, m, 4) // preimageOffset for { let i := 0 } lt(i, 27) { i := add(i, 1) } {
c, m := putField(c, m, 4) // pc let sibling := calldataload(offset)
c, m := putField(c, m, 4) // nextPC offset := add(offset, 32)
c, m := putField(c, m, 4) // lo switch and(shr(i, path), 1)
c, m := putField(c, m, 4) // hi case 0 {
c, m := putField(c, m, 4) // heap node := hashPair(node, sibling)
c, m := putField(c, m, 1) // exitCode } case 1 {
c, m := putField(c, m, 1) // exited node := hashPair(sibling, node)
c, m := putField(c, m, 8) // step }
mstore(m, add(m, 32)) // offset to registers }
m := add(m, 32)
for { let i := 0 } lt(i, 32) { i := add(i, 1) } { c, m := putField(c, m, 4) } // registers // Load the memory root from the first field of state.
let memRoot := mload(0x80)
// Verify the root matches.
if iszero(eq(node, memRoot)) {
mstore(0, 0x0badf00d)
revert(0, 32)
}
// Bits to shift = (32 - 4 - (addr % 32)) * 8
let shamt := shl(3, sub(sub(32, 4), and(_addr, 31)))
out_ := and(shr(shamt, leaf), 0xFFffFFff)
}
} }
if(state.exited) { // don't change state once exited
return outputState(); /// @notice Writes a 32-bit value to memory.
/// This function first overwrites the part of the leaf.
/// Then it recomputes the memory merkle root.
/// @param _addr The address to write to.
/// @param _proofIndex The index of the proof in the calldata.
/// @param _val The value to write.
function writeMem(uint32 _addr, uint8 _proofIndex, uint32 _val) internal pure {
// Compute the offset of the proof in the calldata.
uint256 offset = proofOffset(_proofIndex);
assembly {
// Validate the address alignement.
if and(_addr, 3) {
revert(0, 0)
}
// Load the leaf value.
let leaf := calldataload(offset)
let shamt := shl(3, sub(sub(32, 4), and(_addr, 31)))
// Mask out 4 bytes, and OR in the value
leaf := or(and(leaf, not(shl(shamt, 0xFFffFFff))), shl(shamt, _val))
offset := add(offset, 32)
// Convenience function to hash two nodes together in scratch space.
function hashPair(a, b) -> h {
mstore(0, a)
mstore(32, b)
h := keccak256(0, 64)
}
// Start with the leaf node.
// Work back up by combining with siblings, to reconstruct the root.
let path := shr(5, _addr)
let node := leaf
for { let i := 0 } lt(i, 27) { i := add(i, 1) } {
let sibling := calldataload(offset)
offset := add(offset, 32)
switch and(shr(i, path), 1)
case 0 {
node := hashPair(node, sibling)
} case 1 {
node := hashPair(sibling, node)
}
}
// Store the new memory root in the first field of state.
mstore(0x80, node)
}
} }
state.step += 1;
// instruction fetch /// @notice Executes a single step of the vm.
uint32 insn = readMem(state.pc, 0); /// Will revert if any required input state is missing.
function step(bytes calldata stateData, bytes calldata proof) public returns (bytes32) {
State memory state;
// Packed calldata is ~6 times smaller than state size
assembly {
if iszero(eq(state, 0x80)) { // expected state mem offset check
revert(0,0)
}
if iszero(eq(mload(0x40), mul(32, 48))) { // expected memory check
revert(0,0)
}
if iszero(eq(stateData.offset, 100)) { // 32*3+4=100 expected state data offset
revert(0,0)
}
if iszero(eq(proof.offset, 358)) { // 100+32+226=358 expected proof offset
revert(0,0)
}
function putField(callOffset, memOffset, size) -> callOffsetOut, memOffsetOut {
// calldata is packed, thus starting left-aligned, shift-right to pad and right-align
let w := shr(shl(3, sub(32, size)), calldataload(callOffset))
mstore(memOffset, w)
callOffsetOut := add(callOffset, size)
memOffsetOut := add(memOffset, 32)
}
// Unpack state from calldata into memory
let c := stateData.offset // calldata offset
let m := 0x80 // mem offset
c, m := putField(c, m, 32) // memRoot
c, m := putField(c, m, 32) // preimageKey
c, m := putField(c, m, 4) // preimageOffset
c, m := putField(c, m, 4) // pc
c, m := putField(c, m, 4) // nextPC
c, m := putField(c, m, 4) // lo
c, m := putField(c, m, 4) // hi
c, m := putField(c, m, 4) // heap
c, m := putField(c, m, 1) // exitCode
c, m := putField(c, m, 1) // exited
c, m := putField(c, m, 8) // step
// Unpack register calldata into memory
mstore(m, add(m, 32)) // offset to registers
m := add(m, 32)
for { let i := 0 } lt(i, 32) { i := add(i, 1) } {
c, m := putField(c, m, 4)
}
}
uint32 opcode = insn >> 26; // 6-bits // Don't change state once exited
if (state.exited) {
return outputState();
}
// j-type j/jal state.step += 1;
if (opcode == 2 || opcode == 3) {
// TODO(CLI-4136): likely bug in original code: MIPS spec says this should be in the "current" region;
// a 256 MB aligned region (i.e. use top 4 bits of branch delay slot (pc+4))
return handleJump(opcode == 2 ? 0 : 31, SE(insn&0x03FFFFFF, 26) << 2);
}
// register fetch // instruction fetch
uint32 rs; // source register 1 value uint32 insn = readMem(state.pc, 0);
uint32 rt; // source register 2 / temp value uint32 opcode = insn >> 26; // 6-bits
uint32 rtReg = (insn >> 16) & 0x1F;
// R-type or I-type (stores rt)
rs = state.registers[(insn >> 21) & 0x1F];
uint32 rdReg = rtReg;
if (opcode == 0 || opcode == 0x1c) {
// R-type (stores rd)
rt = state.registers[rtReg];
rdReg = (insn >> 11) & 0x1F;
} else if (opcode < 0x20) {
// rt is SignExtImm
// don't sign extend for andi, ori, xori
if (opcode == 0xC || opcode == 0xD || opcode == 0xe) {
// ZeroExtImm
rt = insn&0xFFFF;
} else {
// SignExtImm
rt = SE(insn&0xFFFF, 16);
}
} else if (opcode >= 0x28 || opcode == 0x22 || opcode == 0x26) {
// store rt value with store
rt = state.registers[rtReg];
// store actual rt with lwl and lwr
rdReg = rtReg;
}
if ((opcode >= 4 && opcode < 8) || opcode == 1) { // j-type j/jal
return handleBranch(opcode, insn, rtReg, rs); if (opcode == 2 || opcode == 3) {
} // TODO(CLI-4136): likely bug in original code: MIPS spec says this should be in the "current" region;
// a 256 MB aligned region (i.e. use top 4 bits of branch delay slot (pc+4))
return handleJump(opcode == 2 ? 0 : 31, SE(insn & 0x03FFFFFF, 26) << 2);
}
uint32 storeAddr = 0xFF_FF_FF_FF; // register fetch
// memory fetch (all I-type) uint32 rs; // source register 1 value
// we do the load for stores also uint32 rt; // source register 2 / temp value
uint32 mem; uint32 rtReg = (insn >> 16) & 0x1F;
if (opcode >= 0x20) {
// M[R[rs]+SignExtImm] // R-type or I-type (stores rt)
rs += SE(insn&0xFFFF, 16); rs = state.registers[(insn >> 21) & 0x1F];
uint32 addr = rs & 0xFFFFFFFC; uint32 rdReg = rtReg;
mem = readMem(addr, 1);
if (opcode >= 0x28 && opcode != 0x30) { if (opcode == 0 || opcode == 0x1c) {
// store // R-type (stores rd)
storeAddr = addr; rt = state.registers[rtReg];
// store opcodes don't write back to a register rdReg = (insn >> 11) & 0x1F;
rdReg = 0; } else if (opcode < 0x20) {
} // rt is SignExtImm
} // don't sign extend for andi, ori, xori
if (opcode == 0xC || opcode == 0xD || opcode == 0xe) {
// ZeroExtImm
rt = insn & 0xFFFF;
} else {
// SignExtImm
rt = SE(insn & 0xFFFF, 16);
}
} else if (opcode >= 0x28 || opcode == 0x22 || opcode == 0x26) {
// store rt value with store
rt = state.registers[rtReg];
// store actual rt with lwl and lwr
rdReg = rtReg;
}
// ALU if ((opcode >= 4 && opcode < 8) || opcode == 1) {
uint32 val = execute(insn, rs, rt, mem) & 0xffFFffFF; // swr outputs more than 4 bytes without the mask return handleBranch(opcode, insn, rtReg, rs);
}
uint32 func = insn & 0x3f; // 6-bits
if (opcode == 0 && func >= 8 && func < 0x1c) {
if (func == 8 || func == 9) { // jr/jalr
return handleJump(func == 8 ? 0 : rdReg, rs);
}
if (func == 0xa) { // movz
return handleRd(rdReg, rs, rt == 0);
}
if (func == 0xb) { // movn
return handleRd(rdReg, rs, rt != 0);
}
// syscall (can read and write)
if (func == 0xC) {
return handleSyscall();
}
// lo and hi registers
// can write back
if (func >= 0x10 && func < 0x1c) {
return handleHiLo(func, rs, rt, rdReg);
}
}
// stupid sc, write a 1 to rt uint32 storeAddr = 0xFF_FF_FF_FF;
if (opcode == 0x38 && rtReg != 0) { // memory fetch (all I-type)
state.registers[rtReg] = 1; // we do the load for stores also
} uint32 mem;
if (opcode >= 0x20) {
// M[R[rs]+SignExtImm]
rs += SE(insn&0xFFFF, 16);
uint32 addr = rs & 0xFFFFFFFC;
mem = readMem(addr, 1);
if (opcode >= 0x28 && opcode != 0x30) {
// store
storeAddr = addr;
// store opcodes don't write back to a register
rdReg = 0;
}
}
// write memory // ALU
if (storeAddr != 0xFF_FF_FF_FF) { uint32 val = execute(insn, rs, rt, mem) & 0xffFFffFF; // swr outputs more than 4 bytes without the mask
writeMem(storeAddr, 1, val);
} uint32 func = insn & 0x3f; // 6-bits
if (opcode == 0 && func >= 8 && func < 0x1c) {
if (func == 8 || func == 9) { // jr/jalr
return handleJump(func == 8 ? 0 : rdReg, rs);
}
if (func == 0xa) { // movz
return handleRd(rdReg, rs, rt == 0);
}
if (func == 0xb) { // movn
return handleRd(rdReg, rs, rt != 0);
}
// syscall (can read and write)
if (func == 0xC) {
return handleSyscall();
}
// lo and hi registers
// can write back
if (func >= 0x10 && func < 0x1c) {
return handleHiLo(func, rs, rt, rdReg);
}
}
// write back the value to destination register // stupid sc, write a 1 to rt
return handleRd(rdReg, val, true); if (opcode == 0x38 && rtReg != 0) {
} state.registers[rtReg] = 1;
}
function execute(uint32 insn, uint32 rs, uint32 rt, uint32 mem) internal pure returns (uint32) {
uint32 opcode = insn >> 26; // 6-bits // write memory
uint32 func = insn & 0x3f; // 6-bits if (storeAddr != 0xFF_FF_FF_FF) {
// TODO(CLI-4136): deref the immed into a register writeMem(storeAddr, 1, val);
}
if (opcode < 0x20) {
// transform ArithLogI // write back the value to destination register
// TODO(CLI-4136): replace with table return handleRd(rdReg, val, true);
if (opcode >= 8 && opcode < 0xF) {
if (opcode == 8) { func = 0x20; } // addi
else if (opcode == 9) { func = 0x21; } // addiu
else if (opcode == 0xa) { func = 0x2a; } // slti
else if (opcode == 0xb) { func = 0x2B; } // sltiu
else if (opcode == 0xc) { func = 0x24; } // andi
else if (opcode == 0xd) { func = 0x25; } // ori
else if (opcode == 0xe) { func = 0x26; } // xori
opcode = 0;
}
// 0 is opcode SPECIAL
if (opcode == 0) {
uint32 shamt = (insn >> 6) & 0x1f;
if (func < 0x20) {
if (func >= 0x08) { return rs; // jr/jalr/div + others
// Shift and ShiftV
} else if (func == 0x00) { return rt << shamt; // sll
} else if (func == 0x02) { return rt >> shamt; // srl
} else if (func == 0x03) { return SE(rt >> shamt, 32-shamt); // sra
} else if (func == 0x04) { return rt << (rs&0x1F); // sllv
} else if (func == 0x06) { return rt >> (rs&0x1F); // srlv
} else if (func == 0x07) { return SE(rt >> rs, 32-rs); // srav
}
}
// 0x10-0x13 = mfhi, mthi, mflo, mtlo
// R-type (ArithLog)
if (func == 0x20 || func == 0x21) { return rs+rt; // add or addu
} else if (func == 0x22 || func == 0x23) { return rs-rt; // sub or subu
} else if (func == 0x24) { return rs&rt; // and
} else if (func == 0x25) { return (rs|rt); // or
} else if (func == 0x26) { return (rs^rt); // xor
} else if (func == 0x27) { return ~(rs|rt); // nor
} else if (func == 0x2a) {
return int32(rs)<int32(rt) ? 1 : 0; // slt
} else if (func == 0x2B) {
return rs<rt ? 1 : 0; // sltu
}
} else if (opcode == 0xf) { return rt<<16; // lui
} else if (opcode == 0x1c) { // SPECIAL2
if (func == 2) return uint32(int32(rs)*int32(rt)); // mul
if (func == 0x20 || func == 0x21) { // clo
if (func == 0x20) rs = ~rs;
uint32 i = 0; while (rs&0x80000000 != 0) { i++; rs <<= 1; } return i;
}
}
} else if (opcode < 0x28) {
if (opcode == 0x20) { // lb
return SE((mem >> (24-(rs&3)*8)) & 0xFF, 8);
} else if (opcode == 0x21) { // lh
return SE((mem >> (16-(rs&2)*8)) & 0xFFFF, 16);
} else if (opcode == 0x22) { // lwl
uint32 val = mem << ((rs&3)*8);
uint32 mask = uint32(0xFFFFFFFF) << ((rs&3)*8);
return (rt & ~mask) | val;
} else if (opcode == 0x23) { return mem; // lw
} else if (opcode == 0x24) { // lbu
return (mem >> (24-(rs&3)*8)) & 0xFF;
} else if (opcode == 0x25) { // lhu
return (mem >> (16-(rs&2)*8)) & 0xFFFF;
} else if (opcode == 0x26) { // lwr
uint32 val = mem >> (24-(rs&3)*8);
uint32 mask = uint32(0xFFFFFFFF) >> (24-(rs&3)*8);
return (rt & ~mask) | val;
}
} else if (opcode == 0x28) { // sb
uint32 val = (rt&0xFF) << (24-(rs&3)*8);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFF << (24-(rs&3)*8));
return (mem & mask) | val;
} else if (opcode == 0x29) { // sh
uint32 val = (rt&0xFFFF) << (16-(rs&2)*8);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFFFF << (16-(rs&2)*8));
return (mem & mask) | val;
} else if (opcode == 0x2a) { // swl
uint32 val = rt >> ((rs&3)*8);
uint32 mask = uint32(0xFFFFFFFF) >> ((rs&3)*8);
return (mem & ~mask) | val;
} else if (opcode == 0x2b) { // sw
return rt;
} else if (opcode == 0x2e) { // swr
uint32 val = rt << (24-(rs&3)*8);
uint32 mask = uint32(0xFFFFFFFF) << (24-(rs&3)*8);
return (mem & ~mask) | val;
} else if (opcode == 0x30) { return mem; // ll
} else if (opcode == 0x38) { return rt; // sc
} }
revert("invalid instruction"); /// @notice Execute an instruction.
} function execute(uint32 insn, uint32 rs, uint32 rt, uint32 mem) internal pure returns (uint32) {
uint32 opcode = insn >> 26; // 6-bits
uint32 func = insn & 0x3f; // 6-bits
// TODO(CLI-4136): deref the immed into a register
if (opcode < 0x20) {
// transform ArithLogI
// TODO(CLI-4136): replace with table
if (opcode >= 8 && opcode < 0xF) {
if (opcode == 8) { func = 0x20; } // addi
else if (opcode == 9) { func = 0x21; } // addiu
else if (opcode == 0xa) { func = 0x2a; } // slti
else if (opcode == 0xb) { func = 0x2B; } // sltiu
else if (opcode == 0xc) { func = 0x24; } // andi
else if (opcode == 0xd) { func = 0x25; } // ori
else if (opcode == 0xe) { func = 0x26; } // xori
opcode = 0;
}
// 0 is opcode SPECIAL
if (opcode == 0) {
uint32 shamt = (insn >> 6) & 0x1f;
if (func < 0x20) {
// jr/jalr/div + others
if (func >= 0x08) {
return rs;
}
// sll: Logical Shift Left
else if (func == 0x00) {
return rt << shamt;
}
// srl: Logical Shift Right
else if (func == 0x02) {
return rt >> shamt;
}
// sra: Arithmetic Shift Right
else if (func == 0x03) {
return SE(rt >> shamt, 32 - shamt);
}
// sllv: Variable Logical Shift Left
else if (func == 0x04) {
return rt << (rs & 0x1F);
}
// srlv: Variable Logical Shift Right
else if (func == 0x06) {
return rt >> (rs & 0x1F);
}
// srav: Variable Arithmetic Shift Right
else if (func == 0x07) {
return SE(rt >> rs, 32 - rs);
}
}
// R-type (ArithLog)
// 0x10-0x13 = mfhi, mthi, mflo, mtlo
// add or addu
if (func == 0x20 || func == 0x21) {
return rs + rt;
}
// sub or subu
else if (func == 0x22 || func == 0x23) {
return rs - rt;
}
// and
else if (func == 0x24) {
return rs & rt;
}
// or
else if (func == 0x25) {
return (rs | rt);
}
// xor
else if (func == 0x26) {
return (rs ^ rt);
}
// nor
else if (func == 0x27) {
return ~(rs | rt);
}
// slt: Set to 1 if less than
else if (func == 0x2a) {
return int32(rs) < int32(rt) ? 1 : 0;
}
// sltu: Set to 1 if less than unsigned
else if (func == 0x2B) {
return rs<rt ? 1 : 0;
}
}
// lui: Load Upper Immediate
else if (opcode == 0xf) {
return rt << 16;
}
// SPECIAL2
else if (opcode == 0x1c) {
// mul
if (func == 2) {
return uint32(int32(rs) * int32(rt));
}
// clo
if (func == 0x20 || func == 0x21) {
if (func == 0x20) {
rs = ~rs;
}
uint32 i = 0;
while (rs&0x80000000 != 0) {
i++;
rs <<= 1;
}
return i;
}
}
}
else if (opcode < 0x28) {
// lb
if (opcode == 0x20) {
return SE((mem >> (24 - (rs & 3) * 8)) & 0xFF, 8);
}
// lh
else if (opcode == 0x21) {
return SE((mem >> (16 - (rs & 2) * 8)) & 0xFFFF, 16);
}
// lwl
else if (opcode == 0x22) {
uint32 val = mem << ((rs & 3) * 8);
uint32 mask = uint32(0xFFFFFFFF) << ((rs & 3) * 8);
return (rt & ~mask) | val;
}
// lw
else if (opcode == 0x23) {
return mem;
}
// lbu
else if (opcode == 0x24) {
return (mem >> (24 - (rs & 3) * 8)) & 0xFF;
}
// lhu
else if (opcode == 0x25) {
return (mem >> (16 - (rs & 2) * 8)) & 0xFFFF;
}
// lwr
else if (opcode == 0x26) {
uint32 val = mem >> (24 - (rs & 3) * 8);
uint32 mask = uint32(0xFFFFFFFF) >> (24 - (rs & 3) * 8);
return (rt & ~mask) | val;
}
}
// sb
else if (opcode == 0x28) {
uint32 val = (rt & 0xFF) << (24 - (rs & 3) * 8);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFF << (24 - (rs & 3) * 8));
return (mem & mask) | val;
}
// sh
else if (opcode == 0x29) {
uint32 val = (rt & 0xFFFF) << (16 - (rs & 2) * 8);
uint32 mask = 0xFFFFFFFF ^ uint32(0xFFFF << (16 - (rs & 2) * 8));
return (mem & mask) | val;
}
// swl
else if (opcode == 0x2a) {
uint32 val = rt >> ((rs & 3) * 8);
uint32 mask = uint32(0xFFFFFFFF) >> ((rs & 3) * 8);
return (mem & ~mask) | val;
}
// sw
else if (opcode == 0x2b) {
return rt;
}
// swr
else if (opcode == 0x2e) {
uint32 val = rt << (24 - (rs & 3) * 8);
uint32 mask = uint32(0xFFFFFFFF) << (24 - (rs & 3) * 8);
return (mem & ~mask) | val;
}
// ll
else if (opcode == 0x30) {
return mem;
}
// sc
else if (opcode == 0x38) {
return rt;
}
revert("invalid instruction");
}
} }
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity ^0.8.15;
/// @title PreimageOracle
/// @notice A contract for storing permissioned pre-images.
contract PreimageOracle { contract PreimageOracle {
/// @notice Mapping of pre-image keys to pre-image lengths.
mapping(bytes32 => uint256) public preimageLengths; mapping(bytes32 => uint256) public preimageLengths;
/// @notice Mapping of pre-image keys to pre-image parts.
mapping(bytes32 => mapping(uint256 => bytes32)) public preimageParts; mapping(bytes32 => mapping(uint256 => bytes32)) public preimageParts;
/// @notice Mapping of pre-image keys to pre-image part offsets.
mapping(bytes32 => mapping(uint256 => bool)) public preimagePartOk; mapping(bytes32 => mapping(uint256 => bool)) public preimagePartOk;
function readPreimage(bytes32 key, uint256 offset) /// @notice Reads a pre-image from the oracle.
/// @param _key The key of the pre-image to read.
/// @param _offset The offset of the pre-image to read.
/// @return dat_ The pre-image data.
/// @return datLen_ The length of the pre-image data.
function readPreimage(bytes32 _key, uint256 _offset)
external external
view view
returns (bytes32 dat, uint256 datLen) returns (bytes32 dat_, uint256 datLen_)
{ {
require(preimagePartOk[key][offset], "preimage must exist"); require(preimagePartOk[_key][_offset], "pre-image must exist");
datLen = 32;
uint256 length = preimageLengths[key]; // Calculate the length of the pre-image data
// add 8 for the length-prefix part // Add 8 for the length-prefix part
if (offset + 32 >= length + 8) { datLen_ = 32;
datLen = length + 8 - offset; uint256 length = preimageLengths[_key];
if (_offset + 32 >= length + 8) {
datLen_ = length + 8 - _offset;
} }
dat = preimageParts[key][offset];
// Retrieve the pre-image data
dat_ = preimageParts[_key][_offset];
} }
// TODO(CLI-4104): // TODO(CLI-4104):
...@@ -37,17 +53,47 @@ contract PreimageOracle { ...@@ -37,17 +53,47 @@ contract PreimageOracle {
preimageLengths[key] = size; preimageLengths[key] = size;
} }
// loadKeccak256PreimagePart prepares the pre-image to be read by keccak256 key, /// @notice Computes and returns the key for a pre-image.
// starting at the given offset, up to 32 bytes (clipped at preimage length, if out of data). /// @param _preimage The pre-image.
function loadKeccak256PreimagePart(uint256 partOffset, bytes calldata preimage) external { /// @return key_ The pre-image key.
function computePreimageKey(bytes calldata _preimage) external pure returns (bytes32 key_) {
uint256 size;
assembly {
size := calldataload(0x24)
// Leave slots 0x40 and 0x60 untouched,
// and everything after as scratch-memory.
let ptr := 0x80
// Store size as a big-endian uint64 at the start of pre-image
mstore(ptr, shl(192, size))
ptr := add(ptr, 8)
// Copy preimage payload into memory so we can hash and read it.
calldatacopy(ptr, _preimage.offset, size)
// Compute the pre-image keccak256 hash (aka the pre-image key)
let h := keccak256(ptr, size)
// Mask out prefix byte, replace with type 2 byte
key_ := or(and(h, not(shl(248, 0xFF))), shl(248, 2))
}
}
/// @notice Prepares a pre-image to be read by keccak256 key, starting at
/// the given offset and up to 32 bytes (clipped at pre-image length, if out of data).
/// @param _partOffset The offset of the pre-image to read.
/// @param _preimage The preimage data.
function loadKeccak256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external {
uint256 size; uint256 size;
bytes32 key; bytes32 key;
bytes32 part; bytes32 part;
assembly { assembly {
// len(sig) + len(partOffset) + len(preimage offset) = 4 + 32 + 32 = 0x44 // len(sig) + len(partOffset) + len(preimage offset) = 4 + 32 + 32 = 0x44
size := calldataload(0x44) size := calldataload(0x44)
// revert if part offset >= size+8 (i.e. parts must be within bounds)
if iszero(lt(partOffset, add(size, 8))) { // revert if part offset > size+8 (i.e. parts must be within bounds)
if gt(_partOffset, add(size, 8)) {
revert(0, 0) revert(0, 0)
} }
// we leave solidity slots 0x40 and 0x60 untouched, // we leave solidity slots 0x40 and 0x60 untouched,
...@@ -57,16 +103,16 @@ contract PreimageOracle { ...@@ -57,16 +103,16 @@ contract PreimageOracle {
mstore(ptr, shl(192, size)) mstore(ptr, shl(192, size))
ptr := add(ptr, 8) ptr := add(ptr, 8)
// copy preimage payload into memory so we can hash and read it. // copy preimage payload into memory so we can hash and read it.
calldatacopy(ptr, preimage.offset, size) calldatacopy(ptr, _preimage.offset, size)
// Note that it includes the 8-byte big-endian uint64 length prefix. // Note that it includes the 8-byte big-endian uint64 length prefix.
// this will be zero-padded at the end, since memory at end is clean. // this will be zero-padded at the end, since memory at end is clean.
part := mload(add(sub(ptr, 8), partOffset)) part := mload(add(sub(ptr, 8), _partOffset))
let h := keccak256(ptr, size) // compute preimage keccak256 hash let h := keccak256(ptr, size) // compute preimage keccak256 hash
// mask out prefix byte, replace with type 2 byte // mask out prefix byte, replace with type 2 byte
key := or(and(h, not(shl(248, 0xFF))), shl(248, 2)) key := or(and(h, not(shl(248, 0xFF))), shl(248, 2))
} }
preimagePartOk[key][partOffset] = true; preimagePartOk[key][_partOffset] = true;
preimageParts[key][partOffset] = part; preimageParts[key][_partOffset] = part;
preimageLengths[key] = size; preimageLengths[key] = size;
} }
} }
// SPDX-License-Identifier: MIT
pragma solidity 0.7.6;
/// @title IPreimageOracle
/// @notice Interface for a preimage oracle.
interface IPreimageOracle {
/// @notice Reads a preimage from the oracle.
/// @param _key The key of the preimage to read.
/// @param _offset The offset of the preimage to read.
/// @return dat_ The preimage data.
/// @return datLen_ The length of the preimage data.
function readPreimage(bytes32 _key, uint256 _offset)
external
view
returns (bytes32 dat_, uint256 datLen_);
/// @notice Computes and returns the key for a pre-image.
/// @param _preimage The pre-image.
/// @return key_ The pre-image key.
function computePreimageKey(bytes calldata _preimage) external pure returns (bytes32 key_);
/// @notice Prepares a preimage to be read by keccak256 key, starting at
/// the given offset and up to 32 bytes (clipped at preimage length, if out of data).
/// @param _partOffset The offset of the preimage to read.
/// @param _preimage The preimage data.
function loadKeccak256PreimagePart(uint256 _partOffset, bytes calldata _preimage) external;
}
...@@ -59,7 +59,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver { ...@@ -59,7 +59,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
Claim _absolutePrestate, Claim _absolutePrestate,
uint256 _maxGameDepth, uint256 _maxGameDepth,
IBigStepper _vm IBigStepper _vm
) Semver(0, 0, 2) { ) Semver(0, 0, 3) {
ABSOLUTE_PRESTATE = _absolutePrestate; ABSOLUTE_PRESTATE = _absolutePrestate;
MAX_GAME_DEPTH = _maxGameDepth; MAX_GAME_DEPTH = _maxGameDepth;
VM = _vm; VM = _vm;
...@@ -92,7 +92,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver { ...@@ -92,7 +92,7 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// Determine the expected pre & post states of the step. // Determine the expected pre & post states of the step.
Claim preStateClaim; Claim preStateClaim;
Claim postStateClaim; ClaimData storage postState;
if (_isAttack) { if (_isAttack) {
if (stepPos.indexAtDepth() == 0) { if (stepPos.indexAtDepth() == 0) {
// If the step position's index at depth is 0, the prestate is the absolute // If the step position's index at depth is 0, the prestate is the absolute
...@@ -104,16 +104,16 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver { ...@@ -104,16 +104,16 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
preStateClaim = findTraceAncestor( preStateClaim = findTraceAncestor(
Position.wrap(Position.unwrap(parentPos) - 1), Position.wrap(Position.unwrap(parentPos) - 1),
parent.parentIndex parent.parentIndex
); ).claim;
} }
// For all attacks, the poststate is the parent claim. // For all attacks, the poststate is the parent claim.
postStateClaim = parent.claim; postState = parent;
} else { } else {
// If the step is a defense, the poststate exists elsewhere in the game state, // If the step is a defense, the poststate exists elsewhere in the game state,
// and the parent claim is the expected pre-state. // and the parent claim is the expected pre-state.
preStateClaim = parent.claim; preStateClaim = parent.claim;
postStateClaim = findTraceAncestor( postState = findTraceAncestor(
Position.wrap(Position.unwrap(parentPos) + 1), Position.wrap(Position.unwrap(parentPos) + 1),
parent.parentIndex parent.parentIndex
); );
...@@ -123,10 +123,21 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver { ...@@ -123,10 +123,21 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
// preimage of the prestate claim hash. // preimage of the prestate claim hash.
if (keccak256(_stateData) != Claim.unwrap(preStateClaim)) revert InvalidPrestate(); if (keccak256(_stateData) != Claim.unwrap(preStateClaim)) revert InvalidPrestate();
// INVARIANT: A VM step can never counter a parent claim unless it produces a poststate // INVARIANT: If a step is an attack, the poststate is valid if the step produces
// that is not equal to the claim at `_parentIndex` if the step is an attack, // the same poststate hash as the parent claim's value.
// or the claim at `_stateIndex` if the step is a defense. // If a step is a defense:
if (VM.step(_stateData, _proof) == Claim.unwrap(postStateClaim)) revert ValidStep(); // 1. If the parent claim and the found post state agree with each other
// (depth diff % 2 == 0), the step is valid if it produces the same
// state hash as the post state's claim.
// 2. If the parent claim and the found post state disagree with each other
// (depth diff % 2 != 0), the parent cannot be countered unless the step
// produces the same state hash as `postState.claim`.
// SAFETY: While the `attack` path does not need an extra check for the post
// state's depth in relation to the parent, we don't need another
// branch because (n - n) % 2 == 0.
bool validStep = VM.step(_stateData, _proof) == Claim.unwrap(postState.claim);
bool parentPostAgree = (parentPos.depth() - postState.position.depth()) % 2 == 0;
if ((parentPostAgree && validStep) || (!parentPostAgree && !validStep)) revert ValidStep();
// Set the parent claim as countered. We do not need to append a new claim to the game; // Set the parent claim as countered. We do not need to append a new claim to the game;
// instead, we can just set the existing parent as countered. // instead, we can just set the existing parent as countered.
...@@ -384,17 +395,16 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver { ...@@ -384,17 +395,16 @@ contract FaultDisputeGame is IFaultDisputeGame, Clone, Semver {
function findTraceAncestor(Position _pos, uint256 _start) function findTraceAncestor(Position _pos, uint256 _start)
internal internal
view view
returns (Claim ancestor_) returns (ClaimData storage ancestor_)
{ {
// Grab the trace ancestor's expected position. // Grab the trace ancestor's expected position.
Position preStateTraceAncestor = _pos.traceAncestor(); Position preStateTraceAncestor = _pos.traceAncestor();
// Walk up the DAG to find a claim that commits to the same trace index as `_pos`. It is // Walk up the DAG to find a claim that commits to the same trace index as `_pos`. It is
// guaranteed that such a claim exists. // guaranteed that such a claim exists.
ClaimData storage ancestor = claimData[_start]; ancestor_ = claimData[_start];
while (Position.unwrap(ancestor.position) != Position.unwrap(preStateTraceAncestor)) { while (Position.unwrap(ancestor_.position) != Position.unwrap(preStateTraceAncestor)) {
ancestor = claimData[ancestor.parentIndex]; ancestor_ = claimData[ancestor_.parentIndex];
} }
ancestor_ = ancestor.claim;
} }
} }
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { AssetReceiver } from "../AssetReceiver.sol"; import { AssetReceiver } from "../AssetReceiver.sol";
import { IDripCheck } from "./IDripCheck.sol"; import { IDripCheck } from "./IDripCheck.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { IDripCheck } from "../IDripCheck.sol"; import { IDripCheck } from "../IDripCheck.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { IDripCheck } from "../IDripCheck.sol"; import { IDripCheck } from "../IDripCheck.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { IDripCheck } from "../IDripCheck.sol"; import { IDripCheck } from "../IDripCheck.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { IDripCheck } from "../IDripCheck.sol"; import { IDripCheck } from "../IDripCheck.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol"; import { Semver } from "../../universal/Semver.sol";
/** /**
* @title AttestationStation * @title AttestationStation
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol"; import { Semver } from "../../universal/Semver.sol";
import { import {
ERC721BurnableUpgradeable ERC721BurnableUpgradeable
} from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol"; } from "@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol";
......
// SPDX-License-Identifier: MIT // SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol"; import { Semver } from "../../universal/Semver.sol";
import { AttestationStation } from "./AttestationStation.sol"; import { AttestationStation } from "./AttestationStation.sol";
import { OptimistConstants } from "./libraries/OptimistConstants.sol"; import { OptimistConstants } from "./libraries/OptimistConstants.sol";
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { OptimistConstants } from "./libraries/OptimistConstants.sol"; import { OptimistConstants } from "./libraries/OptimistConstants.sol";
import { Semver } from "@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol"; import { Semver } from "../../universal/Semver.sol";
import { AttestationStation } from "./AttestationStation.sol"; import { AttestationStation } from "./AttestationStation.sol";
import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol"; import { SignatureChecker } from "@openzeppelin/contracts/utils/cryptography/SignatureChecker.sol";
import { import {
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { AdminFaucetAuthModule } from "../universal/faucet/authmodules/AdminFaucetAuthModule.sol"; import { AdminFaucetAuthModule } from "../periphery/faucet/authmodules/AdminFaucetAuthModule.sol";
import { Faucet } from "../universal/faucet/Faucet.sol"; import { Faucet } from "../periphery/faucet/Faucet.sol";
import { FaucetHelper } from "../testing/helpers/FaucetHelper.sol"; import { FaucetHelper } from "./Helpers.sol";
/** /**
* @title AdminFaucetAuthModuleTest * @title AdminFaucetAuthModuleTest
...@@ -104,7 +104,7 @@ contract AdminFaucetAuthModuleTest is Test { ...@@ -104,7 +104,7 @@ contract AdminFaucetAuthModuleTest is Test {
/** /**
* @notice assert that verify returns true for valid proofs signed by admins. * @notice assert that verify returns true for valid proofs signed by admins.
*/ */
function test_adminProof_verify_returnsTrue() external { function test_adminProof_verify_succeeds() external {
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver"); address fundsReceiver = makeAddr("fundsReceiver");
bytes memory proof = issueProofWithEIP712Domain( bytes memory proof = issueProofWithEIP712Domain(
...@@ -132,7 +132,7 @@ contract AdminFaucetAuthModuleTest is Test { ...@@ -132,7 +132,7 @@ contract AdminFaucetAuthModuleTest is Test {
/** /**
* @notice assert that verify returns false for proofs signed by nonadmins. * @notice assert that verify returns false for proofs signed by nonadmins.
*/ */
function test_nonAdminProof_verify_returnsFalse() external { function test_nonAdminProof_verify_succeeds() external {
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver"); address fundsReceiver = makeAddr("fundsReceiver");
bytes memory proof = issueProofWithEIP712Domain( bytes memory proof = issueProofWithEIP712Domain(
...@@ -161,7 +161,7 @@ contract AdminFaucetAuthModuleTest is Test { ...@@ -161,7 +161,7 @@ contract AdminFaucetAuthModuleTest is Test {
* @notice assert that verify returns false for proofs where the id in the proof is different * @notice assert that verify returns false for proofs where the id in the proof is different
* than the id in the call to verify. * than the id in the call to verify.
*/ */
function test_proofWithWrongId_verify_returnsFalse() external { function test_proofWithWrongId_verify_succeeds() external {
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
address fundsReceiver = makeAddr("fundsReceiver"); address fundsReceiver = makeAddr("fundsReceiver");
address randomAddress = makeAddr("randomAddress"); address randomAddress = makeAddr("randomAddress");
......
...@@ -3,9 +3,9 @@ pragma solidity 0.8.15; ...@@ -3,9 +3,9 @@ pragma solidity 0.8.15;
/* Testing utilities */ /* Testing utilities */
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { TestERC20 } from "../testing/helpers/TestERC20.sol"; import { TestERC20 } from "./Helpers.sol";
import { TestERC721 } from "../testing/helpers/TestERC721.sol"; import { TestERC721 } from "./Helpers.sol";
import { AssetReceiver } from "../universal/AssetReceiver.sol"; import { AssetReceiver } from "../periphery/AssetReceiver.sol";
contract AssetReceiver_Initializer is Test { contract AssetReceiver_Initializer is Test {
address alice = address(128); address alice = address(128);
...@@ -54,12 +54,12 @@ contract AssetReceiver_Initializer is Test { ...@@ -54,12 +54,12 @@ contract AssetReceiver_Initializer is Test {
contract AssetReceiverTest is AssetReceiver_Initializer { contract AssetReceiverTest is AssetReceiver_Initializer {
// Tests if the owner was set correctly during deploy // Tests if the owner was set correctly during deploy
function test_constructor() external { function test_constructor_succeeds() external {
assertEq(address(alice), assetReceiver.owner()); assertEq(address(alice), assetReceiver.owner());
} }
// Tests that receive works as inteded // Tests that receive works as inteded
function test_receive() external { function test_receive_succeeds() external {
// Check that contract balance is 0 initially // Check that contract balance is 0 initially
assertEq(address(assetReceiver).balance, 0); assertEq(address(assetReceiver).balance, 0);
...@@ -75,7 +75,7 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -75,7 +75,7 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// Tests withdrawETH function with only an address as argument, called by owner // Tests withdrawETH function with only an address as argument, called by owner
function test_withdrawETH() external { function test_withdrawETH_succeeds() external {
// Check contract initial balance // Check contract initial balance
assertEq(address(assetReceiver).balance, 0); assertEq(address(assetReceiver).balance, 0);
// Fund contract with 1 eth and check caller and contract balances // Fund contract with 1 eth and check caller and contract balances
...@@ -97,14 +97,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -97,14 +97,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// withdrawETH should fail if called by non-owner // withdrawETH should fail if called by non-owner
function testFail_withdrawETH() external { function test_withdrawETH_unauthorized_reverts() external {
vm.deal(address(assetReceiver), 1 ether); vm.deal(address(assetReceiver), 1 ether);
assetReceiver.withdrawETH(payable(alice));
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawETH(payable(alice));
} }
// Similar as withdrawETH but specify amount to withdraw // Similar as withdrawETH but specify amount to withdraw
function test_withdrawETHwithAmount() external { function test_withdrawETHwithAmount_succeeds() external {
assertEq(address(assetReceiver).balance, 0); assertEq(address(assetReceiver).balance, 0);
vm.deal(address(assetReceiver), 1 ether); vm.deal(address(assetReceiver), 1 ether);
...@@ -125,14 +125,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -125,14 +125,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// withdrawETH with address and amount as arguments called by non-owner // withdrawETH with address and amount as arguments called by non-owner
function testFail_withdrawETHwithAmount() external { function test_withdrawETHwithAmount_unauthorized_reverts() external {
vm.deal(address(assetReceiver), 1 ether); vm.deal(address(assetReceiver), 1 ether);
assetReceiver.withdrawETH(payable(alice), 0.5 ether);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawETH(payable(alice), 0.5 ether);
} }
// Test withdrawERC20 with token and address arguments, from owner // Test withdrawERC20 with token and address arguments, from owner
function test_withdrawERC20() external { function test_withdrawERC20_succeeds() external {
// check balances before the call // check balances before the call
assertEq(testERC20.balanceOf(address(assetReceiver)), 0); assertEq(testERC20.balanceOf(address(assetReceiver)), 0);
...@@ -153,14 +153,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -153,14 +153,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// Same as withdrawERC20 but call from non-owner // Same as withdrawERC20 but call from non-owner
function testFail_withdrawERC20() external { function test_withdrawERC20_unauthorized_reverts() external {
deal(address(testERC20), address(assetReceiver), 100_000); deal(address(testERC20), address(assetReceiver), 100_000);
assetReceiver.withdrawERC20(testERC20, alice);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawERC20(testERC20, alice);
} }
// Similar as withdrawERC20 but specify amount to withdraw // Similar as withdrawERC20 but specify amount to withdraw
function test_withdrawERC20withAmount() external { function test_withdrawERC20withAmount_succeeds() external {
// check balances before the call // check balances before the call
assertEq(testERC20.balanceOf(address(assetReceiver)), 0); assertEq(testERC20.balanceOf(address(assetReceiver)), 0);
...@@ -181,14 +181,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -181,14 +181,14 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// Similar as withdrawERC20 with amount but call from non-owner // Similar as withdrawERC20 with amount but call from non-owner
function testFail_withdrawERC20withAmount() external { function test_withdrawERC20withAmount_unauthorized_reverts() external {
deal(address(testERC20), address(assetReceiver), 100_000); deal(address(testERC20), address(assetReceiver), 100_000);
assetReceiver.withdrawERC20(testERC20, alice, 50_000);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawERC20(testERC20, alice, 50_000);
} }
// Test withdrawERC721 from owner // Test withdrawERC721 from owner
function test_withdrawERC721() external { function test_withdrawERC721_succeeds() external {
// Check owner of the token before calling withdrawERC721 // Check owner of the token before calling withdrawERC721
assertEq(testERC721.ownerOf(DEFAULT_TOKEN_ID), alice); assertEq(testERC721.ownerOf(DEFAULT_TOKEN_ID), alice);
...@@ -209,10 +209,10 @@ contract AssetReceiverTest is AssetReceiver_Initializer { ...@@ -209,10 +209,10 @@ contract AssetReceiverTest is AssetReceiver_Initializer {
} }
// Similar as withdrawERC721 but call from non-owner // Similar as withdrawERC721 but call from non-owner
function testFail_withdrawERC721() external { function test_withdrawERC721_unauthorized_reverts() external {
vm.prank(alice); vm.prank(alice);
testERC721.transferFrom(alice, address(assetReceiver), DEFAULT_TOKEN_ID); testERC721.transferFrom(alice, address(assetReceiver), DEFAULT_TOKEN_ID);
assetReceiver.withdrawERC721(testERC721, alice, DEFAULT_TOKEN_ID);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
assetReceiver.withdrawERC721(testERC721, alice, DEFAULT_TOKEN_ID);
} }
} }
...@@ -3,7 +3,7 @@ pragma solidity 0.8.15; ...@@ -3,7 +3,7 @@ pragma solidity 0.8.15;
/* Testing utilities */ /* Testing utilities */
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../universal/op-nft/AttestationStation.sol"; import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
contract AttestationStation_Initializer is Test { contract AttestationStation_Initializer is Test {
address alice_attestor = address(128); address alice_attestor = address(128);
...@@ -28,7 +28,7 @@ contract AttestationStationTest is AttestationStation_Initializer { ...@@ -28,7 +28,7 @@ contract AttestationStationTest is AttestationStation_Initializer {
bytes val bytes val
); );
function test_attest_individual() external { function test_attest_individual_succeeds() external {
AttestationStation attestationStation = new AttestationStation(); AttestationStation attestationStation = new AttestationStation();
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
...@@ -38,7 +38,7 @@ contract AttestationStationTest is AttestationStation_Initializer { ...@@ -38,7 +38,7 @@ contract AttestationStationTest is AttestationStation_Initializer {
attestationStation.attest({ _about: bob, _key: bytes32("foo"), _val: bytes("bar") }); attestationStation.attest({ _about: bob, _key: bytes32("foo"), _val: bytes("bar") });
} }
function test_attest_single() external { function test_attest_single_succeeds() external {
AttestationStation attestationStation = new AttestationStation(); AttestationStation attestationStation = new AttestationStation();
AttestationStation.AttestationData[] AttestationStation.AttestationData[]
...@@ -100,7 +100,7 @@ contract AttestationStationTest is AttestationStation_Initializer { ...@@ -100,7 +100,7 @@ contract AttestationStationTest is AttestationStation_Initializer {
); );
} }
function test_attest_bulk() external { function test_attest_bulk_succeeds() external {
AttestationStation attestationStation = new AttestationStation(); AttestationStation attestationStation = new AttestationStation();
vm.prank(alice_attestor); vm.prank(alice_attestor);
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { CheckBalanceHigh } from "../universal/drippie/dripchecks/CheckBalanceHigh.sol"; import { CheckBalanceHigh } from "../periphery/drippie/dripchecks/CheckBalanceHigh.sol";
/** /**
* @title CheckBalanceHighTest * @title CheckBalanceHighTest
...@@ -43,7 +43,7 @@ contract CheckBalanceHighTest is Test { ...@@ -43,7 +43,7 @@ contract CheckBalanceHighTest is Test {
* @notice Fuzz the `check` function and assert that it always returns false * @notice Fuzz the `check` function and assert that it always returns false
* when the target's balance is smaller than the threshold. * when the target's balance is smaller than the threshold.
*/ */
function testFuzz_check_fails(address _target, uint256 _threshold) external { function testFuzz_check_lowBalance_fails(address _target, uint256 _threshold) external {
CheckBalanceHigh.Params memory p = CheckBalanceHigh.Params({ CheckBalanceHigh.Params memory p = CheckBalanceHigh.Params({
target: _target, target: _target,
threshold: _threshold threshold: _threshold
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { CheckBalanceLow } from "../universal/drippie/dripchecks/CheckBalanceLow.sol"; import { CheckBalanceLow } from "../periphery/drippie/dripchecks/CheckBalanceLow.sol";
/** /**
* @title CheckBalanceLowTest * @title CheckBalanceLowTest
...@@ -41,7 +41,7 @@ contract CheckBalanceLowTest is Test { ...@@ -41,7 +41,7 @@ contract CheckBalanceLowTest is Test {
* @notice Fuzz the `check` function and assert that it always returns false * @notice Fuzz the `check` function and assert that it always returns false
* when the target's balance is larger than the threshold. * when the target's balance is larger than the threshold.
*/ */
function testFuzz_check_fails(address _target, uint256 _threshold) external { function testFuzz_check_highBalance_fails(address _target, uint256 _threshold) external {
CheckBalanceLow.Params memory p = CheckBalanceLow.Params({ CheckBalanceLow.Params memory p = CheckBalanceLow.Params({
target: _target, target: _target,
threshold: _threshold threshold: _threshold
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { import {
CheckGelatoLow, CheckGelatoLow,
IGelatoTreasury IGelatoTreasury
} from "../universal/drippie/dripchecks/CheckGelatoLow.sol"; } from "../periphery/drippie/dripchecks/CheckGelatoLow.sol";
/** /**
* @title MockGelatoTreasury * @title MockGelatoTreasury
...@@ -78,7 +78,7 @@ contract CheckGelatoLowTest is Test { ...@@ -78,7 +78,7 @@ contract CheckGelatoLowTest is Test {
* when the user's balance in the treasury is greater than or equal * when the user's balance in the treasury is greater than or equal
* to the threshold. * to the threshold.
*/ */
function testFuzz_check_fails(uint256 _threshold, address _recipient) external { function testFuzz_check_highBalance_fails(uint256 _threshold, address _recipient) external {
CheckGelatoLow.Params memory p = CheckGelatoLow.Params({ CheckGelatoLow.Params memory p = CheckGelatoLow.Params({
treasury: address(gelato), treasury: address(gelato),
threshold: _threshold, threshold: _threshold,
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { CheckTrue } from "../universal/drippie/dripchecks/CheckTrue.sol"; import { CheckTrue } from "../periphery/drippie/dripchecks/CheckTrue.sol";
/** /**
* @title CheckTrueTest * @title CheckTrueTest
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.16; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { Drippie } from "../universal/drippie/Drippie.sol"; import { Drippie } from "../periphery/drippie/Drippie.sol";
import { IDripCheck } from "../universal/drippie/IDripCheck.sol"; import { IDripCheck } from "../periphery/drippie/IDripCheck.sol";
import { CheckTrue } from "../universal/drippie/dripchecks/CheckTrue.sol"; import { CheckTrue } from "../periphery/drippie/dripchecks/CheckTrue.sol";
import { SimpleStorage } from "../testing/helpers/SimpleStorage.sol"; import { SimpleStorage } from "./Helpers.sol";
/** /**
* @title TestDrippie * @title TestDrippie
...@@ -149,7 +149,7 @@ contract Drippie_Test is Test { ...@@ -149,7 +149,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Creates a drip and asserts that it was configured as expected. * @notice Creates a drip and asserts that it was configured as expected.
*/ */
function test_create_success() external { function test_create_succeeds() external {
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
emit DripCreated(dripName, dripName, cfg); emit DripCreated(dripName, dripName, cfg);
...@@ -188,7 +188,7 @@ contract Drippie_Test is Test { ...@@ -188,7 +188,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Ensures that the same drip cannot be created two times. * @notice Ensures that the same drip cannot be created two times.
*/ */
function test_create_fails_twice() external { function test_create_calledTwice_reverts() external {
vm.startPrank(drippie.owner()); vm.startPrank(drippie.owner());
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
drippie.create(dripName, cfg); drippie.create(dripName, cfg);
...@@ -200,7 +200,7 @@ contract Drippie_Test is Test { ...@@ -200,7 +200,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Ensures that only the owner of Drippie can create a drip. * @notice Ensures that only the owner of Drippie can create a drip.
*/ */
function testFuzz_fails_unauthorized(address caller) external { function testFuzz_owner_unauthorized_reverts(address caller) external {
vm.assume(caller != drippie.owner()); vm.assume(caller != drippie.owner());
vm.prank(caller); vm.prank(caller);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
...@@ -210,7 +210,7 @@ contract Drippie_Test is Test { ...@@ -210,7 +210,7 @@ contract Drippie_Test is Test {
/** /**
* @notice The owner should be able to set the status of the drip. * @notice The owner should be able to set the status of the drip.
*/ */
function test_set_status_success() external { function test_set_status_succeeds() external {
vm.expectEmit(true, true, true, true); vm.expectEmit(true, true, true, true);
emit DripCreated(dripName, dripName, _defaultConfig()); emit DripCreated(dripName, dripName, _defaultConfig());
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
...@@ -258,7 +258,7 @@ contract Drippie_Test is Test { ...@@ -258,7 +258,7 @@ contract Drippie_Test is Test {
/** /**
* @notice The drip status cannot be set back to NONE after it is created. * @notice The drip status cannot be set back to NONE after it is created.
*/ */
function test_set_status_none_fails() external { function test_set_statusNone_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -272,7 +272,7 @@ contract Drippie_Test is Test { ...@@ -272,7 +272,7 @@ contract Drippie_Test is Test {
* @notice The owner cannot set the status of the drip to the status that * @notice The owner cannot set the status of the drip to the status that
* it is already set as. * it is already set as.
*/ */
function test_set_status_same_fails() external { function test_set_statusSame_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -286,7 +286,7 @@ contract Drippie_Test is Test { ...@@ -286,7 +286,7 @@ contract Drippie_Test is Test {
* @notice The owner should be able to archive the drip if it is in the * @notice The owner should be able to archive the drip if it is in the
* paused state. * paused state.
*/ */
function test_should_archive_if_paused_success() external { function test_shouldArchive_ifPaused_succeeds() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
address owner = drippie.owner(); address owner = drippie.owner();
...@@ -310,7 +310,7 @@ contract Drippie_Test is Test { ...@@ -310,7 +310,7 @@ contract Drippie_Test is Test {
* @notice The owner should not be able to archive the drip if it is in the * @notice The owner should not be able to archive the drip if it is in the
* active state. * active state.
*/ */
function test_should_not_archive_if_active_fails() external { function test_shouldNotArchive_ifActive_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -327,7 +327,7 @@ contract Drippie_Test is Test { ...@@ -327,7 +327,7 @@ contract Drippie_Test is Test {
* @notice The owner should not be allowed to pause the drip if it * @notice The owner should not be allowed to pause the drip if it
* has already been archived. * has already been archived.
*/ */
function test_should_not_allow_paused_if_archived_fails() external { function test_shouldNotAllowPaused_ifArchived_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
_notAllowFromArchive(dripName, Drippie.DripStatus.PAUSED); _notAllowFromArchive(dripName, Drippie.DripStatus.PAUSED);
...@@ -337,7 +337,7 @@ contract Drippie_Test is Test { ...@@ -337,7 +337,7 @@ contract Drippie_Test is Test {
* @notice The owner should not be allowed to make the drip active again if * @notice The owner should not be allowed to make the drip active again if
* it has already been archived. * it has already been archived.
*/ */
function test_should_not_allow_active_if_archived_fails() external { function test_shouldNotAllowActive_ifArchived_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
_notAllowFromArchive(dripName, Drippie.DripStatus.ACTIVE); _notAllowFromArchive(dripName, Drippie.DripStatus.ACTIVE);
...@@ -361,7 +361,7 @@ contract Drippie_Test is Test { ...@@ -361,7 +361,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Attempt to update a drip that does not exist. * @notice Attempt to update a drip that does not exist.
*/ */
function test_name_not_exist_fails() external { function test_name_notExist_reverts() external {
string memory otherName = "bar"; string memory otherName = "bar";
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -376,7 +376,7 @@ contract Drippie_Test is Test { ...@@ -376,7 +376,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Expect a revert when attempting to set the status when not the owner. * @notice Expect a revert when attempting to set the status when not the owner.
*/ */
function test_status_unauthorized_fails() external { function test_status_unauthorized_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
...@@ -386,7 +386,7 @@ contract Drippie_Test is Test { ...@@ -386,7 +386,7 @@ contract Drippie_Test is Test {
/** /**
* @notice The drip should execute and be able to transfer value. * @notice The drip should execute and be able to transfer value.
*/ */
function test_drip_amount() external { function test_drip_amount_succeeds() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -418,7 +418,7 @@ contract Drippie_Test is Test { ...@@ -418,7 +418,7 @@ contract Drippie_Test is Test {
/** /**
* @notice A single DripAction should be able to make a state modifying call. * @notice A single DripAction should be able to make a state modifying call.
*/ */
function test_trigger_one_function() external { function test_trigger_oneFunction_succeeds() external {
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
bytes32 key = bytes32(uint256(2)); bytes32 key = bytes32(uint256(2));
...@@ -455,7 +455,7 @@ contract Drippie_Test is Test { ...@@ -455,7 +455,7 @@ contract Drippie_Test is Test {
/** /**
* @notice Multiple drip actions should be able to be triggered with the same check. * @notice Multiple drip actions should be able to be triggered with the same check.
*/ */
function test_trigger_two_functions() external { function test_trigger_twoFunctions_succeeds() external {
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
Drippie.DripAction[] memory actions = new Drippie.DripAction[](2); Drippie.DripAction[] memory actions = new Drippie.DripAction[](2);
...@@ -516,7 +516,7 @@ contract Drippie_Test is Test { ...@@ -516,7 +516,7 @@ contract Drippie_Test is Test {
* trigger the same drip multiple times in the same interval. Then * trigger the same drip multiple times in the same interval. Then
* move forward to the next interval and it should trigger. * move forward to the next interval and it should trigger.
*/ */
function test_twice_in_one_interval_fails() external { function test_twice_inOneInterval_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
vm.prank(drippie.owner()); vm.prank(drippie.owner());
...@@ -551,7 +551,7 @@ contract Drippie_Test is Test { ...@@ -551,7 +551,7 @@ contract Drippie_Test is Test {
* @notice It should revert if attempting to trigger a drip that does not exist. * @notice It should revert if attempting to trigger a drip that does not exist.
* Note that the drip was never created at the beginning of the test. * Note that the drip was never created at the beginning of the test.
*/ */
function test_drip_not_exist_fails() external { function test_drip_notExist_reverts() external {
vm.prank(drippie.owner()); vm.prank(drippie.owner());
vm.expectRevert("Drippie: selected drip does not exist or is not currently active"); vm.expectRevert("Drippie: selected drip does not exist or is not currently active");
...@@ -562,7 +562,7 @@ contract Drippie_Test is Test { ...@@ -562,7 +562,7 @@ contract Drippie_Test is Test {
/** /**
* @notice The owner cannot trigger the drip when it is paused. * @notice The owner cannot trigger the drip when it is paused.
*/ */
function test_not_active_fails() external { function test_not_active_reverts() external {
_createDefaultDrip(dripName); _createDefaultDrip(dripName);
Drippie.DripStatus status = drippie.dripStatus(dripName); Drippie.DripStatus status = drippie.dripStatus(dripName);
...@@ -598,7 +598,7 @@ contract Drippie_Test is Test { ...@@ -598,7 +598,7 @@ contract Drippie_Test is Test {
* @notice A non zero interval when reentrant is true will cause a revert * @notice A non zero interval when reentrant is true will cause a revert
* when creating a drip. * when creating a drip.
*/ */
function test_reentrant_fails() external { function test_drip_reentrant_reverts() external {
address owner = drippie.owner(); address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
cfg.reentrant = true; cfg.reentrant = true;
...@@ -614,7 +614,7 @@ contract Drippie_Test is Test { ...@@ -614,7 +614,7 @@ contract Drippie_Test is Test {
* @notice If reentrant is false and the interval is 0 then it should * @notice If reentrant is false and the interval is 0 then it should
* revert when the drip is created. * revert when the drip is created.
*/ */
function test_non_reentrant_zero_interval_fails() external { function test_notReentrant_zeroInterval_reverts() external {
address owner = drippie.owner(); address owner = drippie.owner();
Drippie.DripConfig memory cfg = _defaultConfig(); Drippie.DripConfig memory cfg = _defaultConfig();
cfg.reentrant = false; cfg.reentrant = false;
......
...@@ -2,9 +2,9 @@ ...@@ -2,9 +2,9 @@
pragma solidity 0.8.15; pragma solidity 0.8.15;
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { Faucet } from "../universal/faucet/Faucet.sol"; import { Faucet } from "../periphery/faucet/Faucet.sol";
import { AdminFaucetAuthModule } from "../universal/faucet/authmodules/AdminFaucetAuthModule.sol"; import { AdminFaucetAuthModule } from "../periphery/faucet/authmodules/AdminFaucetAuthModule.sol";
import { FaucetHelper } from "../testing/helpers/FaucetHelper.sol"; import { FaucetHelper } from "./Helpers.sol";
contract Faucet_Initializer is Test { contract Faucet_Initializer is Test {
event Drip( event Drip(
...@@ -126,7 +126,7 @@ contract Faucet_Initializer is Test { ...@@ -126,7 +126,7 @@ contract Faucet_Initializer is Test {
} }
contract FaucetTest is Faucet_Initializer { contract FaucetTest is Faucet_Initializer {
function test_initialize() external { function test_initialize_succeeds() external {
assertEq(faucet.ADMIN(), faucetContractAdmin); assertEq(faucet.ADMIN(), faucetContractAdmin);
} }
...@@ -181,7 +181,7 @@ contract FaucetTest is Faucet_Initializer { ...@@ -181,7 +181,7 @@ contract FaucetTest is Faucet_Initializer {
); );
} }
function test_drip_optimistNft_sendsCorrectAmount() external { function test_drip_optimistNftSendsCorrectAmount_succeeds() external {
_enableFaucetAuthModules(); _enableFaucetAuthModules();
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
bytes memory signature = issueProofWithEIP712Domain( bytes memory signature = issueProofWithEIP712Domain(
...@@ -213,7 +213,7 @@ contract FaucetTest is Faucet_Initializer { ...@@ -213,7 +213,7 @@ contract FaucetTest is Faucet_Initializer {
); );
} }
function test_drip_github_sendsCorrectAmount() external { function test_drip_githubSendsCorrectAmount_succeeds() external {
_enableFaucetAuthModules(); _enableFaucetAuthModules();
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
bytes memory signature = issueProofWithEIP712Domain( bytes memory signature = issueProofWithEIP712Domain(
...@@ -241,7 +241,7 @@ contract FaucetTest is Faucet_Initializer { ...@@ -241,7 +241,7 @@ contract FaucetTest is Faucet_Initializer {
); );
} }
function test_drip_emitsEvent() external { function test_drip_emitsEvent_succeeds() external {
_enableFaucetAuthModules(); _enableFaucetAuthModules();
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
bytes memory signature = issueProofWithEIP712Domain( bytes memory signature = issueProofWithEIP712Domain(
...@@ -300,7 +300,7 @@ contract FaucetTest is Faucet_Initializer { ...@@ -300,7 +300,7 @@ contract FaucetTest is Faucet_Initializer {
vm.stopPrank(); vm.stopPrank();
} }
function test_drip_preventsReplayAttacks() external { function test_drip_preventsReplayAttacks_succeeds() external {
_enableFaucetAuthModules(); _enableFaucetAuthModules();
bytes32 nonce = faucetHelper.consumeNonce(); bytes32 nonce = faucetHelper.consumeNonce();
bytes memory signature = issueProofWithEIP712Domain( bytes memory signature = issueProofWithEIP712Domain(
...@@ -423,7 +423,7 @@ contract FaucetTest is Faucet_Initializer { ...@@ -423,7 +423,7 @@ contract FaucetTest is Faucet_Initializer {
vm.stopPrank(); vm.stopPrank();
} }
function test_withdraw_nonAdmin_fails() external { function test_withdraw_nonAdmin_reverts() external {
vm.prank(nonAdmin); vm.prank(nonAdmin);
vm.expectRevert("Faucet: function can only be called by admin"); vm.expectRevert("Faucet: function can only be called by admin");
faucet.withdraw(payable(fundsReceiver), 2 ether); faucet.withdraw(payable(fundsReceiver), 2 ether);
......
...@@ -473,6 +473,14 @@ contract GamePlayer { ...@@ -473,6 +473,14 @@ contract GamePlayer {
counterParty.play(gameProxy.claimDataLen() - 1); counterParty.play(gameProxy.claimDataLen() - 1);
} }
} else { } else {
// Don't defend a claim we would've made ourselves.
if (
parentPos.depth() % 2 == 0 &&
Claim.unwrap(claimAt(15)) == Claim.unwrap(gameProxy.rootClaim())
) {
return;
}
// Defend the parent claim. // Defend the parent claim.
gameProxy.defend(_parentIndex, ourClaim); gameProxy.defend(_parentIndex, ourClaim);
// Call out to our counter party to respond. // Call out to our counter party to respond.
...@@ -488,12 +496,23 @@ contract GamePlayer { ...@@ -488,12 +496,23 @@ contract GamePlayer {
/// @notice Returns the state at the trace index within the player's trace. /// @notice Returns the state at the trace index within the player's trace.
function traceAt(uint256 _traceIndex) public view returns (uint256 state_) { function traceAt(uint256 _traceIndex) public view returns (uint256 state_) {
return uint256(uint8(trace[_traceIndex])); return
uint256(
uint8(_traceIndex >= trace.length ? trace[trace.length - 1] : trace[_traceIndex])
);
} }
/// @notice Returns the player's claim that commits to a given trace index. /// @notice Returns the player's claim that commits to a given trace index.
function claimAt(uint256 _traceIndex) public view returns (Claim claim_) { function claimAt(uint256 _traceIndex) public view returns (Claim claim_) {
return Claim.wrap(keccak256(abi.encode(_traceIndex, traceAt(_traceIndex)))); return
Claim.wrap(
keccak256(
abi.encode(
_traceIndex >= trace.length ? trace.length - 1 : _traceIndex,
traceAt(_traceIndex)
)
)
);
} }
/// @notice Returns the player's claim that commits to a given trace index. /// @notice Returns the player's claim that commits to a given trace index.
...@@ -512,8 +531,14 @@ contract OneVsOne_Arena is FaultDisputeGame_Init { ...@@ -512,8 +531,14 @@ contract OneVsOne_Arena is FaultDisputeGame_Init {
/// @dev The challenger. /// @dev The challenger.
GamePlayer internal challenger; GamePlayer internal challenger;
function init(GamePlayer _defender, GamePlayer _challenger) public { function init(
Claim rootClaim = Claim.wrap(keccak256(abi.encode(15, _defender.traceAt(15)))); GamePlayer _defender,
GamePlayer _challenger,
uint256 _finalTraceIndex
) public {
Claim rootClaim = Claim.wrap(
keccak256(abi.encode(_finalTraceIndex, _defender.traceAt(_finalTraceIndex)))
);
super.init(rootClaim, ABSOLUTE_PRESTATE_CLAIM); super.init(rootClaim, ABSOLUTE_PRESTATE_CLAIM);
defender = _defender; defender = _defender;
challenger = _challenger; challenger = _challenger;
...@@ -532,7 +557,7 @@ contract FaultDisputeGame_ResolvesCorrectly_IncorrectRoot1 is OneVsOne_Arena { ...@@ -532,7 +557,7 @@ contract FaultDisputeGame_ResolvesCorrectly_IncorrectRoot1 is OneVsOne_Arena {
function setUp() public override { function setUp() public override {
GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE); GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE);
GamePlayer dishonest = new FullyDivergentPlayer(ABSOLUTE_PRESTATE); GamePlayer dishonest = new FullyDivergentPlayer(ABSOLUTE_PRESTATE);
super.init(dishonest, honest); super.init(dishonest, honest, 15);
} }
function test_resolvesCorrectly_succeeds() public { function test_resolvesCorrectly_succeeds() public {
...@@ -553,7 +578,7 @@ contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot1 is OneVsOne_Arena { ...@@ -553,7 +578,7 @@ contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot1 is OneVsOne_Arena {
function setUp() public override { function setUp() public override {
GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE); GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE);
GamePlayer dishonest = new FullyDivergentPlayer(ABSOLUTE_PRESTATE); GamePlayer dishonest = new FullyDivergentPlayer(ABSOLUTE_PRESTATE);
super.init(honest, dishonest); super.init(honest, dishonest, 15);
} }
function test_resolvesCorrectly_succeeds() public { function test_resolvesCorrectly_succeeds() public {
...@@ -574,7 +599,7 @@ contract FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2 is OneVsOne_Arena { ...@@ -574,7 +599,7 @@ contract FaultDisputeGame_ResolvesCorrectly_IncorrectRoot2 is OneVsOne_Arena {
function setUp() public override { function setUp() public override {
GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE); GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE);
GamePlayer dishonest = new HalfDivergentPlayer(ABSOLUTE_PRESTATE); GamePlayer dishonest = new HalfDivergentPlayer(ABSOLUTE_PRESTATE);
super.init(dishonest, honest); super.init(dishonest, honest, 15);
} }
function test_resolvesCorrectly_succeeds() public { function test_resolvesCorrectly_succeeds() public {
...@@ -595,7 +620,7 @@ contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot2 is OneVsOne_Arena { ...@@ -595,7 +620,7 @@ contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot2 is OneVsOne_Arena {
function setUp() public override { function setUp() public override {
GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE); GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE);
GamePlayer dishonest = new HalfDivergentPlayer(ABSOLUTE_PRESTATE); GamePlayer dishonest = new HalfDivergentPlayer(ABSOLUTE_PRESTATE);
super.init(honest, dishonest); super.init(honest, dishonest, 15);
} }
function test_resolvesCorrectly_succeeds() public { function test_resolvesCorrectly_succeeds() public {
...@@ -616,7 +641,7 @@ contract FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3 is OneVsOne_Arena { ...@@ -616,7 +641,7 @@ contract FaultDisputeGame_ResolvesCorrectly_IncorrectRoot3 is OneVsOne_Arena {
function setUp() public override { function setUp() public override {
GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE); GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE);
GamePlayer dishonest = new EarlyDivergentPlayer(ABSOLUTE_PRESTATE); GamePlayer dishonest = new EarlyDivergentPlayer(ABSOLUTE_PRESTATE);
super.init(dishonest, honest); super.init(dishonest, honest, 15);
} }
function test_resolvesCorrectly_succeeds() public { function test_resolvesCorrectly_succeeds() public {
...@@ -637,7 +662,91 @@ contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot3 is OneVsOne_Arena { ...@@ -637,7 +662,91 @@ contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot3 is OneVsOne_Arena {
function setUp() public override { function setUp() public override {
GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE); GamePlayer honest = new HonestPlayer(ABSOLUTE_PRESTATE);
GamePlayer dishonest = new EarlyDivergentPlayer(ABSOLUTE_PRESTATE); GamePlayer dishonest = new EarlyDivergentPlayer(ABSOLUTE_PRESTATE);
super.init(honest, dishonest); super.init(honest, dishonest, 15);
}
function test_resolvesCorrectly_succeeds() public {
// Play the game until a step is forced.
challenger.play(0);
// Warp ahead to expire the other player's clock.
vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
// Resolve the game and assert that the dishonest player challenged the root
// claim unsuccessfully.
assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.DEFENDER_WINS));
assertTrue(challenger.failedToStep());
}
}
contract FaultDisputeGame_ResolvesCorrectly_IncorrectRoot4 is OneVsOne_Arena {
function setUp() public override {
GamePlayer honest = new HonestPlayer_HalfTrace(ABSOLUTE_PRESTATE);
GamePlayer dishonest = new DivergentPlayer_HalfTrace(ABSOLUTE_PRESTATE);
super.init(dishonest, honest, 7);
}
function test_resolvesCorrectly_succeeds() public {
// Play the game until a step is forced.
challenger.play(0);
// Warp ahead to expire the other player's clock.
vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
// Resolve the game and assert that the honest player challenged the root
// claim successfully.
assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.CHALLENGER_WINS));
assertFalse(challenger.failedToStep());
}
}
contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot4 is OneVsOne_Arena {
function setUp() public override {
GamePlayer honest = new HonestPlayer_HalfTrace(ABSOLUTE_PRESTATE);
GamePlayer dishonest = new DivergentPlayer_HalfTrace(ABSOLUTE_PRESTATE);
super.init(honest, dishonest, 7);
}
function test_resolvesCorrectly_succeeds() public {
// Play the game until a step is forced.
challenger.play(0);
// Warp ahead to expire the other player's clock.
vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
// Resolve the game and assert that the dishonest player challenged the root
// claim unsuccessfully.
assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.DEFENDER_WINS));
assertTrue(challenger.failedToStep());
}
}
contract FaultDisputeGame_ResolvesCorrectly_IncorrectRoot5 is OneVsOne_Arena {
function setUp() public override {
GamePlayer honest = new HonestPlayer_QuarterTrace(ABSOLUTE_PRESTATE);
GamePlayer dishonest = new DivergentPlayer_QuarterTrace(ABSOLUTE_PRESTATE);
super.init(dishonest, honest, 3);
}
function test_resolvesCorrectly_succeeds() public {
// Play the game until a step is forced.
challenger.play(0);
// Warp ahead to expire the other player's clock.
vm.warp(block.timestamp + 3 days + 12 hours + 1 seconds);
// Resolve the game and assert that the honest player challenged the root
// claim successfully.
assertEq(uint8(gameProxy.resolve()), uint8(GameStatus.CHALLENGER_WINS));
assertFalse(challenger.failedToStep());
}
}
contract FaultDisputeGame_ResolvesCorrectly_CorrectRoot5 is OneVsOne_Arena {
function setUp() public override {
GamePlayer honest = new HonestPlayer_QuarterTrace(ABSOLUTE_PRESTATE);
GamePlayer dishonest = new DivergentPlayer_QuarterTrace(ABSOLUTE_PRESTATE);
super.init(honest, dishonest, 3);
} }
function test_resolvesCorrectly_succeeds() public { function test_resolvesCorrectly_succeeds() public {
...@@ -705,6 +814,52 @@ contract EarlyDivergentPlayer is GamePlayer { ...@@ -705,6 +814,52 @@ contract EarlyDivergentPlayer is GamePlayer {
} }
} }
contract HonestPlayer_HalfTrace is GamePlayer {
constructor(bytes memory _absolutePrestate) {
uint8 absolutePrestate = uint8(_absolutePrestate[31]);
bytes memory halfTrace = new bytes(8);
for (uint8 i = 0; i < halfTrace.length; i++) {
halfTrace[i] = bytes1(absolutePrestate + i + 1);
}
trace = halfTrace;
}
}
contract DivergentPlayer_HalfTrace is GamePlayer {
constructor(bytes memory _absolutePrestate) {
uint8 absolutePrestate = uint8(_absolutePrestate[31]);
bytes memory halfTrace = new bytes(8);
for (uint8 i = 0; i < halfTrace.length; i++) {
// Diverge at trace instruction 5.
halfTrace[i] = i > 4 ? bytes1(i) : bytes1(absolutePrestate + i + 1);
}
trace = halfTrace;
}
}
contract HonestPlayer_QuarterTrace is GamePlayer {
constructor(bytes memory _absolutePrestate) {
uint8 absolutePrestate = uint8(_absolutePrestate[31]);
bytes memory halfTrace = new bytes(4);
for (uint8 i = 0; i < halfTrace.length; i++) {
halfTrace[i] = bytes1(absolutePrestate + i + 1);
}
trace = halfTrace;
}
}
contract DivergentPlayer_QuarterTrace is GamePlayer {
constructor(bytes memory _absolutePrestate) {
uint8 absolutePrestate = uint8(_absolutePrestate[31]);
bytes memory halfTrace = new bytes(4);
for (uint8 i = 0; i < halfTrace.length; i++) {
// Diverge at trace instruction 3.
halfTrace[i] = i > 2 ? bytes1(i) : bytes1(absolutePrestate + i + 1);
}
trace = halfTrace;
}
}
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
// MOCK VMS // // MOCK VMS //
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
......
//SPDX-License-Identifier: MIT //SPDX-License-Identifier: MIT
pragma solidity 0.8.15; pragma solidity ^0.8.0;
import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol";
import { ERC721 } from "@rari-capital/solmate/src/tokens/ERC721.sol";
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import {
ECDSAUpgradeable
} from "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
import { AdminFaucetAuthModule } from "../periphery/faucet/authmodules/AdminFaucetAuthModule.sol";
import { OptimistInviter } from "../../universal/op-nft/OptimistInviter.sol"; contract TestERC20 is ERC20 {
constructor() ERC20("TEST", "TST", 18) {}
function mint(address to, uint256 value) public {
_mint(to, value);
}
}
contract TestERC721 is ERC721 {
constructor() ERC721("TEST", "TST") {}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function tokenURI(uint256) public pure virtual override returns (string memory) {}
}
contract CallRecorder {
struct CallInfo {
address sender;
bytes data;
uint256 gas;
uint256 value;
}
CallInfo public lastCall;
function record() public payable {
lastCall.sender = msg.sender;
lastCall.data = msg.data;
lastCall.gas = gasleft();
lastCall.value = msg.value;
}
}
contract Reverter {
function doRevert() public pure {
revert("Reverter reverted");
}
}
contract SimpleStorage {
mapping(bytes32 => bytes32) public db;
function set(bytes32 _key, bytes32 _value) public payable {
db[_key] = _value;
}
function get(bytes32 _key) public view returns (bytes32) {
return db[_key];
}
}
/** /**
* Simple helper contract that helps with testing flow and signature for OptimistInviter contract. * Simple helper contract that helps with testing flow and signature for OptimistInviter contract.
...@@ -144,3 +205,106 @@ contract OptimistInviterHelper { ...@@ -144,3 +205,106 @@ contract OptimistInviterHelper {
ECDSA.toTypedDataHash(domainSeparator, getClaimableInviteStructHash(_claimableInvite)); ECDSA.toTypedDataHash(domainSeparator, getClaimableInviteStructHash(_claimableInvite));
} }
} }
// solhint-disable max-line-length
/**
* Simple ERC1271 wallet that can be used to test the ERC1271 signature checker.
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/mocks/ERC1271WalletMock.sol
*/
contract TestERC1271Wallet is Ownable, IERC1271 {
constructor(address originalOwner) {
transferOwnership(originalOwner);
}
function isValidSignature(bytes32 hash, bytes memory signature)
public
view
override
returns (bytes4 magicValue)
{
return
ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0);
}
}
/**
* Simple helper contract that helps with testing the Faucet contract.
*/
contract FaucetHelper {
/**
* @notice EIP712 typehash for the Proof type.
*/
bytes32 public constant PROOF_TYPEHASH =
keccak256("Proof(address recipient,bytes32 nonce,bytes32 id)");
/**
* @notice EIP712 typehash for the EIP712Domain type that is included as part of the signature.
*/
bytes32 public constant EIP712_DOMAIN_TYPEHASH =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
/**
* @notice Keeps track of current nonce to generate new nonces for each drip.
*/
uint256 public currentNonce;
/**
* @notice Returns a bytes32 nonce that should change everytime. In practice, people should use
* pseudorandom nonces.
*
* @return Nonce that should be used as part of drip parameters.
*/
function consumeNonce() public returns (bytes32) {
return bytes32(keccak256(abi.encode(currentNonce++)));
}
/**
* @notice Returns the hash of the struct Proof.
*
* @param _proof Proof struct to hash.
*
* @return EIP-712 typed struct hash.
*/
function getProofStructHash(AdminFaucetAuthModule.Proof memory _proof)
public
pure
returns (bytes32)
{
return keccak256(abi.encode(PROOF_TYPEHASH, _proof.recipient, _proof.nonce, _proof.id));
}
/**
* @notice Computes the EIP712 digest with the given domain parameters.
* Used for testing that different domain parameters fail.
*
* @param _proof Proof struct to hash.
* @param _name Contract name to use in the EIP712 domain.
* @param _version Contract version to use in the EIP712 domain.
* @param _chainid Chain ID to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
*
* @return EIP-712 compatible digest.
*/
function getDigestWithEIP712Domain(
AdminFaucetAuthModule.Proof memory _proof,
bytes memory _name,
bytes memory _version,
uint256 _chainid,
address _verifyingContract
) public pure returns (bytes32) {
bytes32 domainSeparator = keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256(_name),
keccak256(_version),
_chainid,
_verifyingContract
)
);
return ECDSAUpgradeable.toTypedDataHash(domainSeparator, getProofStructHash(_proof));
}
}
...@@ -3,11 +3,11 @@ pragma solidity >=0.6.2 <0.9.0; ...@@ -3,11 +3,11 @@ pragma solidity >=0.6.2 <0.9.0;
/* Testing utilities */ /* Testing utilities */
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../universal/op-nft/AttestationStation.sol"; import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
import { Optimist } from "../universal/op-nft/Optimist.sol"; import { Optimist } from "../periphery/op-nft/Optimist.sol";
import { OptimistAllowlist } from "../universal/op-nft/OptimistAllowlist.sol"; import { OptimistAllowlist } from "../periphery/op-nft/OptimistAllowlist.sol";
import { OptimistInviter } from "../universal/op-nft/OptimistInviter.sol"; import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
import { OptimistInviterHelper } from "../testing/helpers/OptimistInviterHelper.sol"; import { OptimistInviterHelper } from "./Helpers.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol"; import { IERC721 } from "@openzeppelin/contracts/token/ERC721/IERC721.sol";
...@@ -29,6 +29,12 @@ interface IMulticall3 { ...@@ -29,6 +29,12 @@ interface IMulticall3 {
returns (Result[] memory returnData); returns (Result[] memory returnData);
} }
library Multicall {
bytes internal constant code =
hex"6080604052600436106100f35760003560e01c80634d2301cc1161008a578063a8b0574e11610059578063a8b0574e1461025a578063bce38bd714610275578063c3077fa914610288578063ee82ac5e1461029b57600080fd5b80634d2301cc146101ec57806372425d9d1461022157806382ad56cb1461023457806386d516e81461024757600080fd5b80633408e470116100c65780633408e47014610191578063399542e9146101a45780633e64a696146101c657806342cbb15c146101d957600080fd5b80630f28c97d146100f8578063174dea711461011a578063252dba421461013a57806327e86d6e1461015b575b600080fd5b34801561010457600080fd5b50425b6040519081526020015b60405180910390f35b61012d610128366004610a85565b6102ba565b6040516101119190610bbe565b61014d610148366004610a85565b6104ef565b604051610111929190610bd8565b34801561016757600080fd5b50437fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0140610107565b34801561019d57600080fd5b5046610107565b6101b76101b2366004610c60565b610690565b60405161011193929190610cba565b3480156101d257600080fd5b5048610107565b3480156101e557600080fd5b5043610107565b3480156101f857600080fd5b50610107610207366004610ce2565b73ffffffffffffffffffffffffffffffffffffffff163190565b34801561022d57600080fd5b5044610107565b61012d610242366004610a85565b6106ab565b34801561025357600080fd5b5045610107565b34801561026657600080fd5b50604051418152602001610111565b61012d610283366004610c60565b61085a565b6101b7610296366004610a85565b610a1a565b3480156102a757600080fd5b506101076102b6366004610d18565b4090565b60606000828067ffffffffffffffff8111156102d8576102d8610d31565b60405190808252806020026020018201604052801561031e57816020015b6040805180820190915260008152606060208201528152602001906001900390816102f65790505b5092503660005b8281101561047757600085828151811061034157610341610d60565b6020026020010151905087878381811061035d5761035d610d60565b905060200281019061036f9190610d8f565b6040810135958601959093506103886020850185610ce2565b73ffffffffffffffffffffffffffffffffffffffff16816103ac6060870187610dcd565b6040516103ba929190610e32565b60006040518083038185875af1925050503d80600081146103f7576040519150601f19603f3d011682016040523d82523d6000602084013e6103fc565b606091505b50602080850191909152901515808452908501351761046d577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260846000fd5b5050600101610325565b508234146104e6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f4d756c746963616c6c333a2076616c7565206d69736d6174636800000000000060448201526064015b60405180910390fd5b50505092915050565b436060828067ffffffffffffffff81111561050c5761050c610d31565b60405190808252806020026020018201604052801561053f57816020015b606081526020019060019003908161052a5790505b5091503660005b8281101561068657600087878381811061056257610562610d60565b90506020028101906105749190610e42565b92506105836020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166105a66020850185610dcd565b6040516105b4929190610e32565b6000604051808303816000865af19150503d80600081146105f1576040519150601f19603f3d011682016040523d82523d6000602084013e6105f6565b606091505b5086848151811061060957610609610d60565b602090810291909101015290508061067d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b50600101610546565b5050509250929050565b43804060606106a086868661085a565b905093509350939050565b6060818067ffffffffffffffff8111156106c7576106c7610d31565b60405190808252806020026020018201604052801561070d57816020015b6040805180820190915260008152606060208201528152602001906001900390816106e55790505b5091503660005b828110156104e657600084828151811061073057610730610d60565b6020026020010151905086868381811061074c5761074c610d60565b905060200281019061075e9190610e76565b925061076d6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff166107906040850185610dcd565b60405161079e929190610e32565b6000604051808303816000865af19150503d80600081146107db576040519150601f19603f3d011682016040523d82523d6000602084013e6107e0565b606091505b506020808401919091529015158083529084013517610851577f08c379a000000000000000000000000000000000000000000000000000000000600052602060045260176024527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060445260646000fd5b50600101610714565b6060818067ffffffffffffffff81111561087657610876610d31565b6040519080825280602002602001820160405280156108bc57816020015b6040805180820190915260008152606060208201528152602001906001900390816108945790505b5091503660005b82811015610a105760008482815181106108df576108df610d60565b602002602001015190508686838181106108fb576108fb610d60565b905060200281019061090d9190610e42565b925061091c6020840184610ce2565b73ffffffffffffffffffffffffffffffffffffffff1661093f6020850185610dcd565b60405161094d929190610e32565b6000604051808303816000865af19150503d806000811461098a576040519150601f19603f3d011682016040523d82523d6000602084013e61098f565b606091505b506020830152151581528715610a07578051610a07576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f4d756c746963616c6c333a2063616c6c206661696c656400000000000000000060448201526064016104dd565b506001016108c3565b5050509392505050565b6000806060610a2b60018686610690565b919790965090945092505050565b60008083601f840112610a4b57600080fd5b50813567ffffffffffffffff811115610a6357600080fd5b6020830191508360208260051b8501011115610a7e57600080fd5b9250929050565b60008060208385031215610a9857600080fd5b823567ffffffffffffffff811115610aaf57600080fd5b610abb85828601610a39565b90969095509350505050565b6000815180845260005b81811015610aed57602081850181015186830182015201610ad1565b81811115610aff576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b600082825180855260208086019550808260051b84010181860160005b84811015610bb1578583037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001895281518051151584528401516040858501819052610b9d81860183610ac7565b9a86019a9450505090830190600101610b4f565b5090979650505050505050565b602081526000610bd16020830184610b32565b9392505050565b600060408201848352602060408185015281855180845260608601915060608160051b870101935082870160005b82811015610c52577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa0888703018452610c40868351610ac7565b95509284019290840190600101610c06565b509398975050505050505050565b600080600060408486031215610c7557600080fd5b83358015158114610c8557600080fd5b9250602084013567ffffffffffffffff811115610ca157600080fd5b610cad86828701610a39565b9497909650939450505050565b838152826020820152606060408201526000610cd96060830184610b32565b95945050505050565b600060208284031215610cf457600080fd5b813573ffffffffffffffffffffffffffffffffffffffff81168114610bd157600080fd5b600060208284031215610d2a57600080fd5b5035919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff81833603018112610dc357600080fd5b9190910192915050565b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112610e0257600080fd5b83018035915067ffffffffffffffff821115610e1d57600080fd5b602001915036819003821315610a7e57600080fd5b8183823760009101908152919050565b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc1833603018112610dc357600080fd5b600082357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa1833603018112610dc357600080fdfea2646970667358221220bb2b5c71a328032f97c676ae39a1ec2148d3e5d6f73d95e9b17910152d61f16264736f6c634300080c0033";
address internal constant addr = 0xcA11bde05977b3631167028862bE2a173976CA11;
}
contract Optimist_Initializer is Test { contract Optimist_Initializer is Test {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Initialized(uint8); event Initialized(uint8);
...@@ -233,8 +239,8 @@ contract Optimist_Initializer is Test { ...@@ -233,8 +239,8 @@ contract Optimist_Initializer is Test {
_optimistAllowlist: optimistAllowlist _optimistAllowlist: optimistAllowlist
}); });
// address test = deployCode("Multicall3.sol"); multicall3 = IMulticall3(Multicall.addr);
multicall3 = IMulticall3(deployCode("Multicall3.sol")); vm.etch(Multicall.addr, Multicall.code);
} }
} }
...@@ -242,7 +248,7 @@ contract OptimistTest is Optimist_Initializer { ...@@ -242,7 +248,7 @@ contract OptimistTest is Optimist_Initializer {
/** /**
* @notice Check that constructor and initializer parameters are correctly set. * @notice Check that constructor and initializer parameters are correctly set.
*/ */
function test_initialize_success() external { function test_initialize_succeeds() external {
// expect name to be set // expect name to be set
assertEq(optimist.name(), name); assertEq(optimist.name(), name);
// expect symbol to be set // expect symbol to be set
...@@ -471,7 +477,7 @@ contract OptimistTest is Optimist_Initializer { ...@@ -471,7 +477,7 @@ contract OptimistTest is Optimist_Initializer {
/** /**
* @notice transferFrom should revert since Optimist is a SBT. * @notice transferFrom should revert since Optimist is a SBT.
*/ */
function test_transferFrom_reverts() external { function test_transferFrom_soulbound_reverts() external {
_mockAllowlistTrueFor(bob); _mockAllowlistTrueFor(bob);
// mint as bob // mint as bob
...@@ -496,7 +502,7 @@ contract OptimistTest is Optimist_Initializer { ...@@ -496,7 +502,7 @@ contract OptimistTest is Optimist_Initializer {
/** /**
* @notice approve should revert since Optimist is a SBT. * @notice approve should revert since Optimist is a SBT.
*/ */
function test_approve_reverts() external { function test_approve_soulbound_reverts() external {
_mockAllowlistTrueFor(bob); _mockAllowlistTrueFor(bob);
// mint as bob // mint as bob
...@@ -514,7 +520,7 @@ contract OptimistTest is Optimist_Initializer { ...@@ -514,7 +520,7 @@ contract OptimistTest is Optimist_Initializer {
/** /**
* @notice setApprovalForAll should revert since Optimist is a SBT. * @notice setApprovalForAll should revert since Optimist is a SBT.
*/ */
function test_setApprovalForAll_reverts() external { function test_setApprovalForAll_soulbound_reverts() external {
_mockAllowlistTrueFor(bob); _mockAllowlistTrueFor(bob);
// mint as bob // mint as bob
......
...@@ -3,11 +3,11 @@ pragma solidity 0.8.15; ...@@ -3,11 +3,11 @@ pragma solidity 0.8.15;
/* Testing utilities */ /* Testing utilities */
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../universal/op-nft/AttestationStation.sol"; import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
import { OptimistAllowlist } from "../universal/op-nft/OptimistAllowlist.sol"; import { OptimistAllowlist } from "../periphery/op-nft/OptimistAllowlist.sol";
import { OptimistInviter } from "../universal/op-nft/OptimistInviter.sol"; import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
import { OptimistInviterHelper } from "../testing/helpers/OptimistInviterHelper.sol"; import { OptimistInviterHelper } from "./Helpers.sol";
import { OptimistConstants } from "../universal/op-nft/libraries/OptimistConstants.sol"; import { OptimistConstants } from "../periphery/op-nft/libraries/OptimistConstants.sol";
contract OptimistAllowlist_Initializer is Test { contract OptimistAllowlist_Initializer is Test {
event AttestationCreated( event AttestationCreated(
......
...@@ -3,13 +3,13 @@ pragma solidity 0.8.15; ...@@ -3,13 +3,13 @@ pragma solidity 0.8.15;
/* Testing utilities */ /* Testing utilities */
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { AttestationStation } from "../universal/op-nft/AttestationStation.sol"; import { AttestationStation } from "../periphery/op-nft/AttestationStation.sol";
import { OptimistInviter } from "../universal/op-nft/OptimistInviter.sol"; import { OptimistInviter } from "../periphery/op-nft/OptimistInviter.sol";
import { Optimist } from "../universal/op-nft/Optimist.sol"; import { Optimist } from "../periphery/op-nft/Optimist.sol";
import { Strings } from "@openzeppelin/contracts/utils/Strings.sol"; import { Strings } from "@openzeppelin/contracts/utils/Strings.sol";
import { TestERC1271Wallet } from "../testing/helpers/TestERC1271Wallet.sol"; import { TestERC1271Wallet } from "./Helpers.sol";
import { OptimistInviterHelper } from "../testing/helpers/OptimistInviterHelper.sol"; import { OptimistInviterHelper } from "./Helpers.sol";
import { OptimistConstants } from "../universal/op-nft/libraries/OptimistConstants.sol"; import { OptimistConstants } from "../periphery/op-nft/libraries/OptimistConstants.sol";
contract OptimistInviter_Initializer is Test { contract OptimistInviter_Initializer is Test {
event InviteClaimed(address indexed issuer, address indexed claimer); event InviteClaimed(address indexed issuer, address indexed claimer);
...@@ -260,7 +260,7 @@ contract OptimistInviter_Initializer is Test { ...@@ -260,7 +260,7 @@ contract OptimistInviter_Initializer is Test {
} }
contract OptimistInviterTest is OptimistInviter_Initializer { contract OptimistInviterTest is OptimistInviter_Initializer {
function test_initialize() external { function test_initialize_succeeds() external {
// expect attestationStation to be set // expect attestationStation to be set
assertEq(address(optimistInviter.ATTESTATION_STATION()), address(attestationStation)); assertEq(address(optimistInviter.ATTESTATION_STATION()), address(attestationStation));
assertEq(optimistInviter.INVITE_GRANTER(), alice_inviteGranter); assertEq(optimistInviter.INVITE_GRANTER(), alice_inviteGranter);
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
import { Test } from "forge-std/Test.sol";
import { PreimageOracle } from "../cannon/PreimageOracle.sol";
contract PreimageOracle_Test is Test {
PreimageOracle oracle;
/// @notice Sets up the testing suite.
function setUp() public {
oracle = new PreimageOracle();
vm.label(address(oracle), "PreimageOracle");
}
/// @notice Test the pre-image key computation with a known pre-image.
function test_computePreimageKey_succeeds() public {
bytes memory preimage = hex"deadbeef";
bytes32 key = oracle.computePreimageKey(preimage);
bytes32 known = 0x02fd4e189132273036449fc9e11198c739161b4c0116a9a2dccdfa1c492006f1;
assertEq(key, known);
}
/// @notice Tests that a pre-image is correctly set.
function test_loadKeccak256PreimagePart_succeeds() public {
// Set the pre-image
bytes memory preimage = hex"deadbeef";
bytes32 key = oracle.computePreimageKey(preimage);
uint256 offset = 0;
oracle.loadKeccak256PreimagePart(offset, preimage);
// Validate the pre-image part
bytes32 part = oracle.preimageParts(key, offset);
bytes32 expectedPart = 0x0000000000000004deadbeef0000000000000000000000000000000000000000;
assertEq(part, expectedPart);
// Validate the pre-image length
uint256 length = oracle.preimageLengths(key);
assertEq(length, preimage.length);
// Validate that the pre-image part is set
bool ok = oracle.preimagePartOk(key, offset);
assertTrue(ok);
}
/// @notice Tests that a pre-image cannot be set with an out-of-bounds offset.
function test_loadKeccak256PreimagePart_outOfBoundsOffset_reverts() public {
bytes memory preimage = hex"deadbeef";
uint256 offset = preimage.length + 9;
vm.expectRevert();
oracle.loadKeccak256PreimagePart(offset, preimage);
}
/// @notice Reading a pre-image part that has not been set should revert.
function testFuzz_readPreimage_missingPreimage_reverts(bytes32 key, uint256 offset) public {
vm.expectRevert("pre-image must exist");
oracle.readPreimage(key, offset);
}
}
...@@ -3,9 +3,9 @@ pragma solidity 0.8.15; ...@@ -3,9 +3,9 @@ pragma solidity 0.8.15;
/* Testing utilities */ /* Testing utilities */
import { Test } from "forge-std/Test.sol"; import { Test } from "forge-std/Test.sol";
import { CallRecorder } from "../testing/helpers/CallRecorder.sol"; import { CallRecorder } from "./Helpers.sol";
import { Reverter } from "../testing/helpers/Reverter.sol"; import { Reverter } from "./Helpers.sol";
import { Transactor } from "../universal/Transactor.sol"; import { Transactor } from "../periphery/Transactor.sol";
contract Transactor_Initializer is Test { contract Transactor_Initializer is Test {
address alice = address(128); address alice = address(128);
...@@ -35,12 +35,12 @@ contract Transactor_Initializer is Test { ...@@ -35,12 +35,12 @@ contract Transactor_Initializer is Test {
contract TransactorTest is Transactor_Initializer { contract TransactorTest is Transactor_Initializer {
// Tests if the owner was set correctly during deploy // Tests if the owner was set correctly during deploy
function test_constructor() external { function test_constructor_succeeds() external {
assertEq(address(alice), transactor.owner()); assertEq(address(alice), transactor.owner());
} }
// Tests CALL, should do a call to target // Tests CALL, should do a call to target
function test_CALL() external { function test_call_succeeds() external {
// Initialize call data // Initialize call data
bytes memory data = abi.encodeWithSelector(callRecorded.record.selector); bytes memory data = abi.encodeWithSelector(callRecorded.record.selector);
// Run CALL // Run CALL
...@@ -50,16 +50,16 @@ contract TransactorTest is Transactor_Initializer { ...@@ -50,16 +50,16 @@ contract TransactorTest is Transactor_Initializer {
} }
// It should revert if called by non-owner // It should revert if called by non-owner
function testFail_CALL() external { function test_call_unauthorized_reverts() external {
// Initialize call data // Initialize call data
bytes memory data = abi.encodeWithSelector(callRecorded.record.selector); bytes memory data = abi.encodeWithSelector(callRecorded.record.selector);
// Run CALL // Run CALL
vm.prank(bob); vm.prank(bob);
transactor.CALL(address(callRecorded), data, 200_000 wei);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
transactor.CALL(address(callRecorded), data, 200_000 wei);
} }
function test_DELEGATECALL() external { function test_delegateCall_succeeds() external {
// Initialize call data // Initialize call data
bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector); bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector);
// Run CALL // Run CALL
...@@ -69,12 +69,12 @@ contract TransactorTest is Transactor_Initializer { ...@@ -69,12 +69,12 @@ contract TransactorTest is Transactor_Initializer {
} }
// It should revert if called by non-owner // It should revert if called by non-owner
function testFail_DELEGATECALLL() external { function test_delegateCall_unauthorized_reverts() external {
// Initialize call data // Initialize call data
bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector); bytes memory data = abi.encodeWithSelector(reverter.doRevert.selector);
// Run CALL // Run CALL
vm.prank(bob); vm.prank(bob);
transactor.DELEGATECALL(address(reverter), data);
vm.expectRevert("UNAUTHORIZED"); vm.expectRevert("UNAUTHORIZED");
transactor.DELEGATECALL(address(reverter), data);
} }
} }
...@@ -44,6 +44,6 @@ ...@@ -44,6 +44,6 @@
"l1GenesisBlockTimestamp": "0x64935846", "l1GenesisBlockTimestamp": "0x64935846",
"l1StartingBlockTag": "earliest", "l1StartingBlockTag": "earliest",
"l2GenesisRegolithTimeOffset": "0x0", "l2GenesisRegolithTimeOffset": "0x0",
"faultGameAbsolutePrestate": 15, "faultGameAbsolutePrestate": 140,
"faultGameMaxDepth": 4 "faultGameMaxDepth": 4
} }
\ No newline at end of file
...@@ -107,7 +107,7 @@ const main = async () => { ...@@ -107,7 +107,7 @@ const main = async () => {
// Check the rest. // Check the rest.
for (const { check, error } of checks) { for (const { check, error } of checks) {
if (!check(element.name.split('_'))) { if (!check(element.name.split('_'))) {
errors.push(`${filepath} function ${element.name}: ${error}`) errors.push(`${filepath}#${element.name}: ${error}`)
success = false success = false
} }
} }
......
ignores: [
"@eth-optimism/contracts-bedrock",
"@openzeppelin/contracts",
"@openzeppelin/contracts-upgradeable",
"@ethersproject/providers",
"@ethersproject/abi",
"@rari-capital/solmate",
"@types/node",
"hardhat-deploy",
"ts-node",
"typescript",
"prettier-plugin-solidity",
"solhint-plugin-prettier",
"@babel/eslint-parser",
"@typescript-eslint/parser",
"eslint-plugin-import",
"eslint-plugin-unicorn",
"eslint-plugin-jsdoc",
"eslint-plugin-prefer-arrow",
"eslint-plugin-react",
"mkdirp",
"@typescript-eslint/eslint-plugin",
"eslint-config-prettier",
"eslint-plugin-prettier",
"chai",
"babel-eslint",
"ds-test",
"forge-std"
]
# Etherscan API key for Ethereum and Ethereum testnets
ETHEREUM_ETHERSCAN_API_KEY=
# Etherscan API key for Optimism and Optimism testnets
OPTIMISTIC_ETHERSCAN_API_KEY=
# Insert your Ledger address here if using a Ledger to deploy
LEDGER_ADDRESS=
# Alternatively you can use a private key, but leave Ledger blank if so
PRIVATE_KEY=
# Required to deploy to Ethereum or Ethereum testnets
INFURA_PROJECT_ID=
module.exports = {
extends: '../../.eslintrc.js',
}
AssetReceiverTest:testFail_withdrawERC20() (gas: 199012)
AssetReceiverTest:testFail_withdrawERC20withAmount() (gas: 199092)
AssetReceiverTest:testFail_withdrawERC721() (gas: 55908)
AssetReceiverTest:testFail_withdrawETH() (gas: 10457)
AssetReceiverTest:testFail_withdrawETHwithAmount() (gas: 10594)
AssetReceiverTest:test_constructor() (gas: 9794)
AssetReceiverTest:test_receive() (gas: 21010)
AssetReceiverTest:test_withdrawERC20() (gas: 185529)
AssetReceiverTest:test_withdrawERC20withAmount() (gas: 184609)
AssetReceiverTest:test_withdrawERC721() (gas: 51565)
AssetReceiverTest:test_withdrawETH() (gas: 28774)
AssetReceiverTest:test_withdrawETHwithAmount() (gas: 28703)
AssetReceiverTest:test_attest_bulk() (gas: 611417)
AssetReceiverTest:test_attest_individual() (gas: 538536)
AssetReceiverTest:test_attest_single() (gas: 558939)
CheckBalanceHighTest:testFuzz_check_fails(address,uint256) (runs: 256, μ: 12352, ~: 12382)
CheckBalanceHighTest:testFuzz_check_succeeds(address,uint256) (runs: 256, μ: 10284, ~: 10284)
CheckBalanceLowTest:testFuzz_check_fails(address,uint256) (runs: 256, μ: 10262, ~: 10262)
CheckBalanceLowTest:testFuzz_check_succeeds(address,uint256) (runs: 256, μ: 12374, ~: 12404)
CheckGelatoLowTest:testFuzz_check_fails(uint256,address) (runs: 256, μ: 34938, ~: 35871)
CheckGelatoLowTest:testFuzz_check_succeeds(uint256,address) (runs: 256, μ: 18800, ~: 18800)
CheckTrueTest:testFuzz_always_true_succeeds(bytes) (runs: 256, μ: 6539, ~: 6486)
Drippie_Test:testFuzz_fails_unauthorized(address) (runs: 256, μ: 17073, ~: 17073)
Drippie_Test:test_create_fails_twice() (gas: 169499)
Drippie_Test:test_create_success() (gas: 184013)
Drippie_Test:test_drip_amount() (gas: 286156)
Drippie_Test:test_drip_not_exist_fails() (gas: 15136)
Drippie_Test:test_name_not_exist_fails() (gas: 16157)
Drippie_Test:test_non_reentrant_zero_interval_fails() (gas: 19090)
Drippie_Test:test_not_active_fails() (gas: 171861)
Drippie_Test:test_reentrant_fails() (gas: 19129)
Drippie_Test:test_reentrant_succeeds() (gas: 180769)
Drippie_Test:test_set_status_none_fails() (gas: 169439)
Drippie_Test:test_set_status_same_fails() (gas: 169939)
Drippie_Test:test_set_status_success() (gas: 199270)
Drippie_Test:test_should_archive_if_paused_success() (gas: 177922)
Drippie_Test:test_should_not_allow_active_if_archived_fails() (gas: 175362)
Drippie_Test:test_should_not_allow_paused_if_archived_fails() (gas: 175383)
Drippie_Test:test_should_not_archive_if_active_fails() (gas: 176512)
Drippie_Test:test_status_unauthorized_fails() (gas: 167971)
Drippie_Test:test_trigger_one_function() (gas: 339137)
Drippie_Test:test_trigger_two_functions() (gas: 493184)
Drippie_Test:test_twice_in_one_interval_fails() (gas: 305202)
OptimistTest:test_optimist_baseURI() (gas: 116809)
OptimistTest:test_optimist_burn() (gas: 77526)
OptimistTest:test_optimist_initialize() (gas: 23095)
OptimistTest:test_optimist_is_on_allow_list() (gas: 52616)
OptimistTest:test_optimist_mint_already_minted() (gas: 98823)
OptimistTest:test_optimist_mint_happy_path() (gas: 99175)
OptimistTest:test_optimist_mint_no_attestation() (gas: 15897)
OptimistTest:test_optimist_mint_secondary_minter() (gas: 100576)
OptimistTest:test_optimist_sbt_approve() (gas: 97284)
OptimistTest:test_optimist_sbt_transfer() (gas: 102331)
OptimistTest:test_optimist_set_approval_for_all() (gas: 100907)
OptimistTest:test_optimist_supports_interface() (gas: 5797)
OptimistTest:test_optimist_token_id_of_owner() (gas: 95045)
OptimistTest:test_optimist_token_uri() (gas: 213972)
TransactorTest:testFail_CALL() (gas: 15636)
TransactorTest:testFail_DELEGATECALLL() (gas: 15632)
TransactorTest:test_CALL() (gas: 26969)
TransactorTest:test_DELEGATECALL() (gas: 21189)
TransactorTest:test_constructor() (gas: 9772)
"*.{ts,js}":
- eslint
"*.sol":
- pnpm solhint -f table
module.exports = {
...require('../../.prettierrc.js'),
}
module.exports = {
skipFiles: [
'./test-libraries',
'./foundry-tests',
'./testing'
],
mocha: {
grep: "@skip-on-coverage",
invert: true
}
};
{
"extends": "solhint:recommended",
"plugins": ["prettier"],
"rules": {
"prettier/prettier": "error",
"compiler-version": "off",
"code-complexity": ["warn", 5],
"max-line-length": ["error", 100],
"func-param-name-mixedcase": "error",
"modifier-name-mixedcase": "error",
"ordering": "warn",
"not-rely-on-time": "off",
"no-complex-fallback": "off",
"not-rely-on-block-hash": "off",
"reentrancy": "off",
"contract-name-camelcase": "off"
}
}
node_modules
contracts/foundry-tests/*.t.sol
# @eth-optimism/contracts-periphery
## 1.0.8
### Patch Changes
- 2129dafa3: Add faucet contract
- 188d1e930: Change type for auth id on Faucet contracts from bytes to bytes32
## 1.0.7
### Patch Changes
- 4c64a5811: Update the attestation station impl to 1.1.0
## 1.0.6
### Patch Changes
- 0222215f6: Manually update the version on the contracts-bedrock dep.
## 1.0.5
### Patch Changes
- fe8f2afd0: Minor fix to AttestationStation test
- 886fec5bb: Add attestation contracts
- 596d51852: Update zeppelin deps in contracts periphery
- c12aeb2f9: Add deploy script for attestations tation
- a610b4f3b: Make zeppelin deps in contracts periphery not get hoisted
- 55515ba14: Add some default options to optimist config
- bf5f9febd: Add authors to optimist contracts
- 9a996a13c: Make deploy scripts a little safer
- 09924e8ed: Add test coverage script to contracts periphery
- 746ce5545: Add deployment scripts for optimist
- 0e0546a11: Add optimist contract
## 1.0.4
### Patch Changes
- 1d3c749a2: Bumps the version of ts-node used
## 1.0.3
### Patch Changes
- f49b71d50: Updated forge-std version
## 1.0.2
### Patch Changes
- e81a6ff5: Goerli nft bridge deployment
- a3242d4f: Fix erc721 factory to match erc21 factory
- ffa5297e: mainnet nft bridge deployments
## 1.0.1
### Patch Changes
- 02c457a5: Removes NFT refund logic if withdrawals fail.
- d3fe9b6d: Adds input validation to the ERC721Bridge constructor, fixes a typo in the L1ERC721Bridge, and removes the ERC721Refunded event declaration.
- 220ad4ef: Remove ownable upgradable from erc721 factory
- 5d86ff0e: Increased solc version on drip checks to 0.8.16.
## 1.0.0
### Major Changes
- 5c3f2b1f: Fixes NFT bridge related contracts in response to the OpenZeppelin audit. Updates tests to support these changes, including integration tests.
### Patch Changes
- 3883f34b: Remove ERC721Refunded events
## 0.2.4
### Patch Changes
- 7215f4ce: Bump ethers to 5.7.0 globally
- 0ceff8b8: Drippie Spearbit audit fix for issues #32 and #33, clarify behavior of executable function
- 0ceff8b8: Drippie Spearbit audit fix for issue #25, reorder DripStatus enum for clarity
- 0ceff8b8: Drippie Spearbit audit fix for issue #44, document drip count and increment before external calls
- 0ceff8b8: Drippie Spearbit audit fix for issue 24, use call over transfer for withdrawETH
- 0ceff8b8: Drippie Spearbit audit fix for issue 22, remove unnecessary gas parameter
- 0ceff8b8: Drippie Spearbit audit fix for issue #34, missing natspec
- 0ceff8b8: Drippie Spearbit audit fix for issue #28, document dripcheck behavior in drip function
- 0ceff8b8: Drippie Spearbit audit fix #42, remove unnecessary SLOADs in the status function
- 0ceff8b8: Drippie Spearbit audit fix for issue #39, update to latest version of Solidity
- 0ceff8b8: Drippie Spearbit audit fix for issue #21, use correct version of Solmate
- 0ceff8b8: Drippie Spearbit audit fix for issue #31, require explicit opt-in for reentrant drips
- 0ceff8b8: Drippie Spearbit audit fix for issue #45, calldata over memory to save gas
- 0ceff8b8: Drippie Spearbit audit fix for issue #35, correct contract layout ordering
## 0.2.3
### Patch Changes
- f4bf4f52: Fixes import paths in the contracts-periphery package
## 0.2.2
### Patch Changes
- ea371af2: Support deploy via Ledger or private key
## 0.2.1
### Patch Changes
- 93d3bd41: Update compiler version to 0.8.15
- bcfd1edc: Add compiler 0.8.15
- 0bf3b9b4: Update forge-std
## 0.2.0
### Minor Changes
- 8a335b7b: Fixes a bug in the OptimismMintableERC721. Requires an interface change, so this is a minor and not patch.
### Patch Changes
- 95fc3fbf: Add typechain with ethers v5 support
- 019657db: Add TeleportrDeposit and TeleportrDisburser to contracts-periphery
- 6ff5c0a3: Cleaned up natspec for Drippie and its dependencies
- 119f0e97: Moves TeleportrWithdrawer to L1 contracts folder
- 9c8b1f00: Bump forge-std to 62caef29b0f87a2c6aaaf634b2ca4c09b6867c92
- 89d01f2e: Update dev deps
## 0.1.5
### Patch Changes
- 3799bb6f: Deploy Drippie to mainnet
## 0.1.4
### Patch Changes
- 9aa8049c: Deploy NFT bridge contracts
## 0.1.3
### Patch Changes
- da1633a3: ERC721 bridge from Eth Mainnet to Optimism
- 61a30273: Simplify, cleanup, and standardize ERC721 bridge contracts.
- a320e744: Updates contracts-periphery to use the standardized hardhat deploy config plugin
- 29ff7462: Revert es target back to 2017
- 604dd315: Deploy Drippie to kovan and OP kovan
## 0.1.2
### Patch Changes
- e0b89fcd: Re-deploy RetroReceiver
- 982cb980: Tweaks Drippie contract for client-side ease
- 9142adc4: Adds new TeleportrWithdrawer contract for withdrawing from Teleportr
## 0.1.1
### Patch Changes
- 416d2e60: Introduce the Drippie peripheral contract for managing ETH drips
## 0.1.0
### Minor Changes
- f7d964d7: Releases the first version of the contracts-periphery package
### Patch Changes
- d18ae135: Updates all ethers versions in response to BN.js bug
- Updated dependencies [d18ae135]
- @eth-optimism/core-utils@0.8.5
(The MIT License)
Copyright 2020-2021 Optimism
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Optimism Peripheral Smart Contracts
[![codecov](https://codecov.io/gh/ethereum-optimism/optimism/branch/develop/graph/badge.svg?token=0VTG7PG7YR&flag=contracts-periphery-tests)](https://codecov.io/gh/ethereum-optimism/optimism)
checks:
- name: eth-gas-reporter/codechecks
settings:
speculativeBranchSelection: false
branches:
- develop
- master
import { DeployConfig } from '../../src'
const config: DeployConfig = {
ddd: '0x9C6373dE60c2D3297b18A8f964618ac46E011B58',
l2ProxyOwnerAddress: '',
optimistName: '',
optimistSymbol: '',
optimistBaseUriAttestorAddress: '',
optimistInviterInviteGranter: '',
optimistInviterName: '',
optimistAllowlistAllowlistAttestor: '',
optimistAllowlistCoinbaseQuestAttestor: '',
}
export default config
import { DeployConfig } from '../../src'
const config: DeployConfig = {
ddd: '0x9C6373dE60c2D3297b18A8f964618ac46E011B58',
l2ProxyOwnerAddress: '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistName: 'Optimist',
optimistSymbol: 'OPTIMIST',
optimistBaseUriAttestorAddress: '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistInviterInviteGranter: '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistInviterName: 'OptimistInviter',
optimistAllowlistAllowlistAttestor:
'0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistAllowlistCoinbaseQuestAttestor:
'0x661B7Acca8ebd93AFd349a088e9a9A00053DB1BF',
}
export default config
import { DeployConfig } from '../../src'
const config: DeployConfig = {
ddd: '0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266',
l2ProxyOwnerAddress: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
optimistName: 'OP Citizenship',
optimistSymbol: 'OPNFT',
optimistBaseUriAttestorAddress: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
optimistInviterInviteGranter: '0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
optimistInviterName: 'OptimistInviter',
optimistAllowlistAllowlistAttestor:
'0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
optimistAllowlistCoinbaseQuestAttestor:
'0x70997970c51812dc3a010c7d01b50e0d17dc79c8',
}
export default config
import config from './hardhat'
// uses the same config as hardhat.ts
export default config
import { DeployConfig } from '../../src'
const config: DeployConfig = {
ddd: '0x9C6373dE60c2D3297b18A8f964618ac46E011B58',
l2ProxyOwnerAddress: '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistName: 'Optimist',
optimistSymbol: 'OPTIMIST',
optimistBaseUriAttestorAddress: '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistInviterInviteGranter: '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistInviterName: 'OptimistInviter',
optimistAllowlistAllowlistAttestor:
'0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistAllowlistCoinbaseQuestAttestor:
'0x661B7Acca8ebd93AFd349a088e9a9A00053DB1BF',
}
export default config
import { DeployConfig } from '../../src'
const config: DeployConfig = {
ddd: '0x9C6373dE60c2D3297b18A8f964618ac46E011B58',
// EcoPod test account
l2ProxyOwnerAddress: '0x8F0EBDaA1cF7106bE861753B0f9F5c0250fE0819',
optimistName: 'Optimist',
optimistSymbol: 'OPTIMIST',
optimistBaseUriAttestorAddress: '0x8F0EBDaA1cF7106bE861753B0f9F5c0250fE0819',
optimistInviterInviteGranter: '0x8F0EBDaA1cF7106bE861753B0f9F5c0250fE0819',
optimistInviterName: 'OptimistInviter',
optimistAllowlistAllowlistAttestor:
'0x8F0EBDaA1cF7106bE861753B0f9F5c0250fE0819',
optimistAllowlistCoinbaseQuestAttestor:
'0x9A75024c09b48B78205dfCf9D9FC5E026CD9A416',
}
export default config
import { DeployConfig } from '../../src'
const config: DeployConfig = {
ddd: '0x9C6373dE60c2D3297b18A8f964618ac46E011B58',
l2ProxyOwnerAddress: '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistName: 'Optimist',
optimistSymbol: 'OPTIMIST',
optimistBaseUriAttestorAddress: '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistInviterInviteGranter: '0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistInviterName: 'OptimistInviter',
optimistAllowlistAllowlistAttestor:
'0x60c5C9c98bcBd0b0F2fD89B24c16e533BaA8CdA3',
optimistAllowlistCoinbaseQuestAttestor:
'0x661B7Acca8ebd93AFd349a088e9a9A00053DB1BF',
}
export default config
import { ethers } from 'ethers'
import { DrippieConfig } from '../../src'
const config: DrippieConfig = {
TeleportrWithdrawalV2: {
interval: 60 * 60 * 24,
dripcheck: 'CheckBalanceHigh',
checkparams: {
target: '0x52ec2f3d7c5977a8e558c8d9c6000b615098e8fc',
threshold: ethers.utils.parseEther('1'),
},
actions: [
{
target: '0x78A25524D90E3D0596558fb43789bD800a5c3007',
data: {
fn: 'withdrawFromTeleportr',
args: [],
},
},
],
},
GelatoBalance: {
interval: 60 * 60 * 24,
dripcheck: 'CheckGelatoLow',
checkparams: {
treasury: '0x2807B4aE232b624023f87d0e237A3B1bf200Fd99',
recipient: '0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
threshold: ethers.utils.parseEther('0.1'),
},
actions: [
{
target: '0x2807B4aE232b624023f87d0e237A3B1bf200Fd99',
value: ethers.utils.parseEther('1'),
data: {
fn: 'depositFunds',
args: [
// receiver
'0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
// token
'0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
// amount
ethers.utils.parseEther('1'),
],
},
},
],
},
}
export default config
import { ethers } from 'ethers'
import { DrippieConfig, Time } from '../../src'
const config: DrippieConfig = {
BatcherBalance: {
interval: 1 * Time.DAY,
dripcheck: 'CheckBalanceLow',
checkparams: {
target: '0x7431310e026b69bfc676c0013e12a1a11411eec9',
threshold: ethers.utils.parseEther('50'),
},
actions: [
{
target: '0x7431310e026b69bfc676c0013e12a1a11411eec9',
value: ethers.utils.parseEther('100'),
},
],
},
ProposerBalance: {
interval: 1 * Time.DAY,
dripcheck: 'CheckBalanceLow',
checkparams: {
target: '0x02b1786a85ec3f71fbbba46507780db7cf9014f6',
threshold: ethers.utils.parseEther('50'),
},
actions: [
{
target: '0x02b1786a85ec3f71fbbba46507780db7cf9014f6',
value: ethers.utils.parseEther('100'),
},
],
},
GelatoBalance: {
interval: 1 * Time.DAY,
dripcheck: 'CheckGelatoLow',
checkparams: {
treasury: '0xf381dfd7a139caab83c26140e5595c0b85ddadcd',
recipient: '0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
threshold: ethers.utils.parseEther('0.1'),
},
actions: [
{
target: '0xf381dfd7a139caab83c26140e5595c0b85ddadcd',
value: ethers.utils.parseEther('1'),
data: {
fn: 'depositFunds',
args: [
// receiver
'0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
// token
'0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
// amount
ethers.utils.parseEther('1'),
],
},
},
],
},
}
export default config
import { ethers } from 'ethers'
import { DrippieConfig, Time } from '../../src'
const config: DrippieConfig = {
TeleportrWithdrawal: {
interval: 10 * Time.MINUTE,
dripcheck: 'CheckBalanceHigh',
checkparams: {
target: '0x4821975ca220601c153d02353300d6ad34adc362',
threshold: ethers.utils.parseEther('1'),
},
actions: [
{
target: '0x78A25524D90E3D0596558fb43789bD800a5c3007',
data: {
fn: 'withdrawFromTeleportr',
args: [],
},
},
],
},
GelatoBalance: {
interval: 1 * Time.DAY,
dripcheck: 'CheckGelatoLow',
checkparams: {
treasury: '0x340759c8346A1E6Ed92035FB8B6ec57cE1D82c2c',
recipient: '0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
threshold: ethers.utils.parseEther('0.1'),
},
actions: [
{
target: '0x340759c8346A1E6Ed92035FB8B6ec57cE1D82c2c',
value: ethers.utils.parseEther('1'),
data: {
fn: 'depositFunds',
args: [
// receiver
'0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
// token
'0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
// amount
ethers.utils.parseEther('1'),
],
},
},
],
},
}
export default config
import { ethers } from 'ethers'
import { DrippieConfig, Time } from '../../src'
const config: DrippieConfig = {
BatcherBalance: {
interval: 1 * Time.DAY,
dripcheck: 'CheckBalanceLow',
checkparams: {
target: '0x6887246668a3b87f54deb3b94ba47a6f63f32985',
threshold: ethers.utils.parseEther('75'),
},
actions: [
{
target: '0x6887246668a3b87f54deb3b94ba47a6f63f32985',
value: ethers.utils.parseEther('125'),
},
],
},
ProposerBalance: {
interval: 1 * Time.DAY,
dripcheck: 'CheckBalanceLow',
checkparams: {
target: '0x473300df21d047806a082244b417f96b32f13a33',
threshold: ethers.utils.parseEther('50'),
},
actions: [
{
target: '0x473300df21d047806a082244b417f96b32f13a33',
value: ethers.utils.parseEther('100'),
},
],
},
GelatoBalance: {
interval: 1 * Time.DAY,
dripcheck: 'CheckGelatoLow',
checkparams: {
treasury: '0x2807B4aE232b624023f87d0e237A3B1bf200Fd99',
recipient: '0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
threshold: ethers.utils.parseEther('0.1'),
},
actions: [
{
target: '0x2807B4aE232b624023f87d0e237A3B1bf200Fd99',
value: ethers.utils.parseEther('1'),
data: {
fn: 'depositFunds',
args: [
// receiver
'0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
// token
'0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
// amount
ethers.utils.parseEther('1'),
],
},
},
],
},
}
export default config
import { ethers } from 'ethers'
import { DrippieConfig, Time } from '../../src'
const config: DrippieConfig = {
GelatoBalance: {
interval: 1 * Time.DAY,
dripcheck: 'CheckGelatoLow',
checkparams: {
treasury: '0x527a819db1eb0e34426297b03bae11F2f8B3A19E',
recipient: '0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
threshold: ethers.utils.parseEther('0.1'),
},
actions: [
{
target: '0x527a819db1eb0e34426297b03bae11F2f8B3A19E',
value: ethers.utils.parseEther('1'),
data: {
fn: 'depositFunds',
args: [
// receiver
'0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5',
// token
'0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee',
// amount
ethers.utils.parseEther('1'),
],
},
},
],
},
TonyOptimismKovanFaucet: {
interval: 1 * Time.WEEK,
dripcheck: 'CheckBalanceLow',
checkparams: {
target: '0xa8019d6F7bC3008a0a708A422f223Ccb21b61eAD',
threshold: ethers.utils.parseEther('20'),
},
actions: [
{
target: '0xa8019d6F7bC3008a0a708A422f223Ccb21b61eAD',
value: ethers.utils.parseEther('100'),
},
],
},
}
export default config
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { Multicall3 } from "multicall/src/Multicall3.sol";
/**
* Just exists so we can compile this contract.
*/
contract MulticallContractCompiler {
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract CallRecorder {
struct CallInfo {
address sender;
bytes data;
uint256 gas;
uint256 value;
}
CallInfo public lastCall;
function record() public payable {
lastCall.sender = msg.sender;
lastCall.data = msg.data;
lastCall.gas = gasleft();
lastCall.value = msg.value;
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { ProxyAdmin } from "@eth-optimism/contracts-bedrock/contracts/universal/ProxyAdmin.sol";
import { Proxy } from "@eth-optimism/contracts-bedrock/contracts/universal/Proxy.sol";
/**
* Just exists so we can compile external contracts.
*/
contract ExternalContractCompiler {
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract FailingReceiver {
receive() external payable {
require(false, "FailingReceiver");
}
}
//SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import {
AdminFaucetAuthModule
} from "../../universal/faucet/authmodules/AdminFaucetAuthModule.sol";
import {
ECDSAUpgradeable
} from "@openzeppelin/contracts-upgradeable/utils/cryptography/ECDSAUpgradeable.sol";
/**
* Simple helper contract that helps with testing the Faucet contract.
*/
contract FaucetHelper {
/**
* @notice EIP712 typehash for the Proof type.
*/
bytes32 public constant PROOF_TYPEHASH =
keccak256("Proof(address recipient,bytes32 nonce,bytes32 id)");
/**
* @notice EIP712 typehash for the EIP712Domain type that is included as part of the signature.
*/
bytes32 public constant EIP712_DOMAIN_TYPEHASH =
keccak256(
"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
);
/**
* @notice Keeps track of current nonce to generate new nonces for each drip.
*/
uint256 public currentNonce;
/**
* @notice Returns a bytes32 nonce that should change everytime. In practice, people should use
* pseudorandom nonces.
*
* @return Nonce that should be used as part of drip parameters.
*/
function consumeNonce() public returns (bytes32) {
return bytes32(keccak256(abi.encode(currentNonce++)));
}
/**
* @notice Returns the hash of the struct Proof.
*
* @param _proof Proof struct to hash.
*
* @return EIP-712 typed struct hash.
*/
function getProofStructHash(AdminFaucetAuthModule.Proof memory _proof)
public
pure
returns (bytes32)
{
return keccak256(abi.encode(PROOF_TYPEHASH, _proof.recipient, _proof.nonce, _proof.id));
}
/**
* @notice Computes the EIP712 digest with the given domain parameters.
* Used for testing that different domain parameters fail.
*
* @param _proof Proof struct to hash.
* @param _name Contract name to use in the EIP712 domain.
* @param _version Contract version to use in the EIP712 domain.
* @param _chainid Chain ID to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
* @param _verifyingContract Address to use in the EIP712 domain.
*
* @return EIP-712 compatible digest.
*/
function getDigestWithEIP712Domain(
AdminFaucetAuthModule.Proof memory _proof,
bytes memory _name,
bytes memory _version,
uint256 _chainid,
address _verifyingContract
) public pure returns (bytes32) {
bytes32 domainSeparator = keccak256(
abi.encode(
EIP712_DOMAIN_TYPEHASH,
keccak256(_name),
keccak256(_version),
_chainid,
_verifyingContract
)
);
return ECDSAUpgradeable.toTypedDataHash(domainSeparator, getProofStructHash(_proof));
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract Reverter {
function doRevert() public pure {
revert("Reverter reverted");
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
contract SimpleStorage {
mapping(bytes32 => bytes32) public db;
function set(bytes32 _key, bytes32 _value) public payable {
db[_key] = _value;
}
function get(bytes32 _key) public view returns (bytes32) {
return db[_key];
}
}
// SPDX-License-Identifier: MIT
pragma solidity 0.8.15;
import { IERC1271 } from "@openzeppelin/contracts/interfaces/IERC1271.sol";
import { Ownable } from "@openzeppelin/contracts/access/Ownable.sol";
import { ECDSA } from "@openzeppelin/contracts/utils/cryptography/ECDSA.sol";
// solhint-disable max-line-length
/**
* Simple ERC1271 wallet that can be used to test the ERC1271 signature checker.
* https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/mocks/ERC1271WalletMock.sol
*/
contract TestERC1271Wallet is Ownable, IERC1271 {
constructor(address originalOwner) {
transferOwnership(originalOwner);
}
function isValidSignature(bytes32 hash, bytes memory signature)
public
view
override
returns (bytes4 magicValue)
{
return
ECDSA.recover(hash, signature) == owner() ? this.isValidSignature.selector : bytes4(0);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { ERC20 } from "@rari-capital/solmate/src/tokens/ERC20.sol";
contract TestERC20 is ERC20 {
constructor() ERC20("TEST", "TST", 18) {}
function mint(address to, uint256 value) public {
_mint(to, value);
}
}
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import { ERC721 } from "@rari-capital/solmate/src/tokens/ERC721.sol";
contract TestERC721 is ERC721 {
constructor() ERC721("TEST", "TST") {}
function mint(address to, uint256 tokenId) public {
_mint(to, tokenId);
}
function tokenURI(uint256) public pure virtual override returns (string memory) {}
}
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = await hre.deployments.deterministic(
'PeripheryProxyAdmin',
{
contract: 'ProxyAdmin',
salt: hre.ethers.utils.solidityKeccak256(
['string'],
['PeripheryProxyAdmin']
),
from: deployer,
args: [hre.deployConfig.ddd],
log: true,
}
)
await deploy()
}
deployFn.tags = ['PeripheryProxyAdmin']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = await hre.deployments.deterministic('AssetReceiver', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['RetroReceiver']),
from: deployer,
args: [hre.deployConfig.ddd],
log: true,
})
await deploy()
}
deployFn.tags = ['RetroReceiver']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = await hre.deployments.deterministic('Drippie', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['Drippie']),
from: deployer,
args: [hre.deployConfig.ddd],
log: true,
})
await deploy()
}
deployFn.tags = ['Drippie', 'DrippieEnvironment']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = await hre.deployments.deterministic('CheckBalanceHigh', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['CheckBalanceHigh']),
from: deployer,
log: true,
})
await deploy()
}
deployFn.tags = ['CheckBalanceHigh', 'DrippieEnvironment']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = await hre.deployments.deterministic('CheckBalanceLow', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['CheckBalanceLow']),
from: deployer,
log: true,
})
await deploy()
}
deployFn.tags = ['CheckBalanceLow', 'DrippieEnvironment']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = await hre.deployments.deterministic('CheckGelatoLow', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['CheckGelatoLow']),
from: deployer,
log: true,
})
await deploy()
}
deployFn.tags = ['CheckGelatoLow', 'DrippieEnvironment']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
const deployFn: DeployFunction = async (hre) => {
const { deployer } = await hre.getNamedAccounts()
const { deploy } = await hre.deployments.deterministic('CheckTrue', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['CheckTrue']),
from: deployer,
log: true,
})
await deploy()
}
deployFn.tags = ['CheckTrue', 'DrippieEnvironment']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
const deployFn: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const { deployer } = await hre.getNamedAccounts()
console.log(`Deploying AttestationStation with ${deployer}`)
const { deploy } = await hre.deployments.deterministic('AttestationStation', {
salt: hre.ethers.utils.solidityKeccak256(
['string'],
['AttestationStation']
),
from: deployer,
args: [],
log: true,
})
await deploy()
const Deployment__AttestationStation = await hre.deployments.get(
'AttestationStation'
)
const addr = Deployment__AttestationStation.address
console.log(`AttestationStation deployed to ${addr}`)
}
deployFn.tags = ['AttestationStation', 'OptimistEnvironment']
export default deployFn
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { assertContractVariable } from '@eth-optimism/contracts-bedrock/src/deploy-utils'
import { ethers, utils } from 'ethers'
import type { DeployConfig } from '../../src'
const { getAddress } = utils
/**
* Deploys the AttestationStationProxy
*/
const deployFn: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const deployConfig = hre.deployConfig as DeployConfig
const { deployer } = await hre.getNamedAccounts()
const ddd = hre.deployConfig.ddd
if (getAddress(deployer) !== getAddress(ddd)) {
throw new Error('Must deploy with the ddd')
}
console.log(`Deploying AttestationStationProxy with ${deployer}`)
const Deployment__AttestationStation = await hre.deployments.get(
'AttestationStation'
)
const { deploy } = await hre.deployments.deterministic(
'AttestationStationProxy',
{
salt: hre.ethers.utils.solidityKeccak256(
['string'],
['AttestationStationProxy']
),
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
}
)
await deploy()
const Deployment__AttestationStationProxy = await hre.deployments.get(
'AttestationStationProxy'
)
const addr = Deployment__AttestationStationProxy.address
console.log(`AttestationStationProxy deployed to ${addr}`)
console.log(
`Using AttestationStation implementation at ${Deployment__AttestationStation.address}`
)
const Proxy = await hre.ethers.getContractAt('Proxy', addr)
const AttestationStation = await hre.ethers.getContractAt(
'AttestationStation',
addr
)
const implementation = await Proxy.connect(
ethers.constants.AddressZero
).callStatic.implementation()
console.log(`implementation is set to ${implementation}`)
if (
getAddress(implementation) !==
getAddress(Deployment__AttestationStation.address)
) {
console.log('implementation not set to AttestationStation contract')
console.log(
`Setting implementation to ${Deployment__AttestationStation.address}`
)
const tx = await Proxy.upgradeTo(Deployment__AttestationStation.address)
const receipt = await tx.wait()
console.log(`implementation set in tx ${receipt.transactionHash}`)
} else {
console.log('implementation already set to AttestationStation contract')
}
const l2ProxyOwnerAddress = deployConfig.l2ProxyOwnerAddress
const admin = await Proxy.connect(
ethers.constants.AddressZero
).callStatic.admin()
console.log(`admin is set to ${admin}`)
if (getAddress(admin) !== getAddress(l2ProxyOwnerAddress)) {
console.log('admin not set correctly')
console.log(`Setting admin to ${l2ProxyOwnerAddress}`)
const tx = await Proxy.changeAdmin(l2ProxyOwnerAddress)
const receipt = await tx.wait()
console.log(`admin set in ${receipt.transactionHash}`)
} else {
console.log('admin already set to L2 Proxy Owner Address')
}
console.log('Contract deployment complete')
await assertContractVariable(Proxy, 'admin', l2ProxyOwnerAddress)
await assertContractVariable(AttestationStation, 'version', '1.1.0')
}
deployFn.tags = ['AttestationStationProxy', 'OptimistEnvironment']
deployFn.dependencies = ['AttestationStation']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import type { DeployConfig } from '../../src'
const deployFn: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const deployConfig = hre.deployConfig as DeployConfig
const { deployer } = await hre.getNamedAccounts()
console.log(`Deploying OptimistAllowlist implementation with ${deployer}`)
const Deployment__AttestationStation = await hre.deployments.get(
'AttestationStationProxy'
)
const Deployment__OptimistInviter = await hre.deployments.get(
'OptimistInviterProxy'
)
const attestationStationAddress = Deployment__AttestationStation.address
const optimistInviterAddress = Deployment__OptimistInviter.address
console.log(`Using ${attestationStationAddress} as the ATTESTATION_STATION`)
console.log(
`Using ${deployConfig.optimistAllowlistAllowlistAttestor} as ALLOWLIST_ATTESTOR`
)
console.log(
`Using ${deployConfig.optimistAllowlistCoinbaseQuestAttestor} as COINBASE_QUEST_ATTESTOR`
)
console.log(`Using ${optimistInviterAddress} as OPTIMIST_INVITER`)
const { deploy } = await hre.deployments.deterministic('OptimistAllowlist', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['OptimistAllowlist']),
from: deployer,
args: [
attestationStationAddress,
deployConfig.optimistAllowlistAllowlistAttestor,
deployConfig.optimistAllowlistCoinbaseQuestAttestor,
optimistInviterAddress,
],
log: true,
})
await deploy()
}
deployFn.tags = ['OptimistAllowlistImpl', 'OptimistEnvironment']
deployFn.dependencies = ['AttestationStationProxy', 'OptimistInviterProxy']
export default deployFn
/* Imports: External */
import assert from 'assert'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { assertContractVariable } from '@eth-optimism/contracts-bedrock/src/deploy-utils'
import { ethers, utils } from 'ethers'
import type { DeployConfig } from '../../src'
import { setupProxyContract } from '../../src/helpers/setupProxyContract'
const { getAddress } = utils
// Required conditions before deploying - Specified in `deployFn.dependencies`
// - AttestationStationProxy is deployed and points to the correct implementation
// - OptimistInviterProxy is deployed and points to the correct implementation
// - OptimistAllowlistImpl is deployed
//
// Steps
// 1. Deploy OptimistAllowlistProxy
// 2. Point the newly deployed proxy to the implementation, if it hasn't been done already
// 3. Update the admin of the proxy to the l2ProxyOwnerAddress, if it hasn't been done already
// 4. Basic sanity checks for contract variables
const deployFn: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const deployConfig = hre.deployConfig as DeployConfig
// Deployer should be set in hardhat.config.ts
const { deployer } = await hre.getNamedAccounts()
// We want the ability to deploy to a deterministic address, so we need the init bytecode to be
// consistent across deployments. The ddd will quickly transfer the ownership of the Proxy to a
// multisig after deployment.
//
// We need a consistent ddd, since the Proxy takes a `_admin` constructor argument, which
// affects the init bytecode and hence deployed address.
const ddd = deployConfig.ddd
if (getAddress(deployer) !== getAddress(ddd)) {
// Not a hard requirement. We can deploy with any account and just set the `_admin` to the
// ddd, but requiring that the deployer is the same as the ddd minimizes number of hot wallets
// we need to keep track of during deployment.
throw new Error('Must deploy with the ddd')
}
// Get the up to date deployment of the OptimistAllowlist contract
const Deployment__OptimistAllowlistImpl = await hre.deployments.get(
'OptimistAllowlist'
)
console.log(`Deploying OptimistAllowlistProxy with ${deployer}`)
// Deploys the Proxy.sol contract with the `_admin` constructor param set to the ddd (=== deployer).
const { deploy } = await hre.deployments.deterministic(
'OptimistAllowlistProxy',
{
salt: hre.ethers.utils.solidityKeccak256(
['string'],
['OptimistAllowlistProxy']
),
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
}
)
// Deploy the Proxy contract
await deploy()
const Deployment__OptimistAllowlistProxy = await hre.deployments.get(
'OptimistAllowlistProxy'
)
console.log(
`OptimistAllowlistProxy deployed to ${Deployment__OptimistAllowlistProxy.address}`
)
// Deployed Proxy.sol contract
const Proxy = await hre.ethers.getContractAt(
'Proxy',
Deployment__OptimistAllowlistProxy.address
)
// Deployed Proxy.sol contract with the OptimistAllowlist interface
const OptimistAllowlist = await hre.ethers.getContractAt(
'OptimistAllowlist',
Deployment__OptimistAllowlistProxy.address
)
// ethers.Signer for the ddd. Should be the current owner of the Proxy.
const dddSigner = await hre.ethers.provider.getSigner(deployer)
// intended admin of the Proxy
const l2ProxyOwnerAddress = deployConfig.l2ProxyOwnerAddress
// setup the Proxy contract with correct implementation and admin
await setupProxyContract(Proxy, dddSigner, {
targetImplAddress: Deployment__OptimistAllowlistImpl.address,
targetProxyOwnerAddress: l2ProxyOwnerAddress,
})
const Deployment__AttestationStationProxy = await hre.deployments.get(
'AttestationStationProxy'
)
const Deployment__OptimistInviter = await hre.deployments.get(
'OptimistInviterProxy'
)
await assert(
getAddress(
await Proxy.connect(ethers.constants.AddressZero).callStatic.admin()
) === getAddress(l2ProxyOwnerAddress)
)
await assertContractVariable(OptimistAllowlist, 'version', '1.0.0')
await assertContractVariable(
OptimistAllowlist,
'ATTESTATION_STATION',
Deployment__AttestationStationProxy.address
)
await assertContractVariable(
OptimistAllowlist,
'ALLOWLIST_ATTESTOR',
deployConfig.optimistAllowlistAllowlistAttestor
)
await assertContractVariable(
OptimistAllowlist,
'COINBASE_QUEST_ATTESTOR',
deployConfig.optimistAllowlistCoinbaseQuestAttestor
)
await assertContractVariable(
OptimistAllowlist,
'OPTIMIST_INVITER',
Deployment__OptimistInviter.address
)
}
deployFn.tags = ['OptimistAllowlistProxy', 'OptimistEnvironment']
deployFn.dependencies = [
'AttestationStationProxy',
'OptimistInviterProxy',
'OptimistAllowlistImpl',
]
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import type { DeployConfig } from '../../src'
const deployFn: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const deployConfig = hre.deployConfig as DeployConfig
const { deployer } = await hre.getNamedAccounts()
console.log(`Deploying Optimist implementation with ${deployer}`)
const Deployment__AttestationStationProxy = await hre.deployments.get(
'AttestationStationProxy'
)
const attestationStationAddress = Deployment__AttestationStationProxy.address
console.log(`Using ${attestationStationAddress} as the ATTESTATION_STATION`)
console.log(
`Using ${deployConfig.optimistBaseUriAttestorAddress} as BASE_URI_ATTESTOR`
)
const Deployment__OptimistAllowlistProxy = await hre.deployments.get(
'OptimistAllowlistProxy'
)
const optimistAllowlistAddress = Deployment__OptimistAllowlistProxy.address
const { deploy } = await hre.deployments.deterministic('Optimist', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['Optimist']),
from: deployer,
args: [
deployConfig.optimistName,
deployConfig.optimistSymbol,
deployConfig.optimistBaseUriAttestorAddress,
attestationStationAddress,
optimistAllowlistAddress,
],
log: true,
})
await deploy()
}
deployFn.tags = ['OptimistImpl', 'OptimistEnvironment']
deployFn.dependencies = ['AttestationStationProxy', 'OptimistAllowlistProxy']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import '@nomiclabs/hardhat-ethers'
import '@eth-optimism/hardhat-deploy-config'
import 'hardhat-deploy'
import type { DeployConfig } from '../../src'
const deployFn: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const deployConfig = hre.deployConfig as DeployConfig
const { deployer } = await hre.getNamedAccounts()
console.log(`Deploying OptimistInviter implementation with ${deployer}`)
const Deployment__AttestationStation = await hre.deployments.get(
'AttestationStationProxy'
)
const attestationStationAddress = Deployment__AttestationStation.address
console.log(`Using ${attestationStationAddress} as the ATTESTATION_STATION`)
console.log(
`Using ${deployConfig.optimistInviterInviteGranter} as INVITE_GRANTER`
)
const { deploy } = await hre.deployments.deterministic('OptimistInviter', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['OptimistInviter']),
from: deployer,
args: [
deployConfig.optimistInviterInviteGranter,
attestationStationAddress,
],
log: true,
})
await deploy()
}
deployFn.tags = ['OptimistInviterImpl', 'OptimistEnvironment']
deployFn.dependencies = ['AttestationStationProxy']
export default deployFn
/* Imports: External */
import assert from 'assert'
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { assertContractVariable } from '@eth-optimism/contracts-bedrock/src/deploy-utils'
import { ethers, utils } from 'ethers'
import type { DeployConfig } from '../../src'
import { setupProxyContract } from '../../src/helpers/setupProxyContract'
const { getAddress } = utils
// Required conditions before deploying - Specified in `deployFn.dependencies`
// - AttestationStationProxy is deployed and points to the correct implementation
// - OptimistInviterImpl is deployed
//
// Steps
// 1. Deploy OptimistInviterProxy
// 2. Point the newly deployed proxy to the implementation, if it hasn't been done already
// 3. Update the admin of the proxy to the l2ProxyOwnerAddress, if it hasn't been done already
// 4. Basic sanity checks for contract variables
const deployFn: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const deployConfig = hre.deployConfig as DeployConfig
// Deployer should be set in hardhat.config.ts
const { deployer } = await hre.getNamedAccounts()
// We want the ability to deploy to a deterministic address, so we need the init bytecode to be
// consistent across deployments. The ddd will quickly transfer the ownership of the Proxy to a
// multisig after deployment.
//
// We need a consistent ddd, since the Proxy takes a `_admin` constructor argument, which
// affects the init bytecode and hence deployed address.
const ddd = deployConfig.ddd
if (getAddress(deployer) !== getAddress(ddd)) {
// Not a hard requirement. We can deploy with any account and just set the `_admin` to the
// ddd, but requiring that the deployer is the same as the ddd minimizes number of hot wallets
// we need to keep track of during deployment.
throw new Error('Must deploy with the ddd')
}
// Get the up to date deployment of the OptimistInviter contract
const Deployment__OptimistInviterImpl = await hre.deployments.get(
'OptimistInviter'
)
console.log(`Deploying OptimistInviterProxy with ${deployer}`)
// Deploys the Proxy.sol contract with the `_admin` constructor param set to the ddd (=== deployer).
const { deploy } = await hre.deployments.deterministic(
'OptimistInviterProxy',
{
salt: hre.ethers.utils.solidityKeccak256(
['string'],
['OptimistInviterProxy']
),
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
}
)
// Deploy the Proxy contract
await deploy()
const Deployment__OptimistInviterProxy = await hre.deployments.get(
'OptimistInviterProxy'
)
console.log(
`OptimistInviterProxy deployed to ${Deployment__OptimistInviterProxy.address}`
)
// Deployed Proxy.sol contract
const Proxy = await hre.ethers.getContractAt(
'Proxy',
Deployment__OptimistInviterProxy.address
)
// Deployed Proxy.sol contract with the OptimistInviter interface
const OptimistInviter = await hre.ethers.getContractAt(
'OptimistInviter',
Deployment__OptimistInviterProxy.address
)
const name = deployConfig.optimistInviterName
// Create the calldata for the call to `initialize()`
const initializeCalldata = OptimistInviter.interface.encodeFunctionData(
'initialize',
[name]
)
// ethers.Signer for the ddd. Should be the current owner of the Proxy.
const dddSigner = await hre.ethers.provider.getSigner(deployer)
// intended admin of the Proxy
const l2ProxyOwnerAddress = deployConfig.l2ProxyOwnerAddress
// setup the Proxy contract with correct implementation and admin
await setupProxyContract(Proxy, dddSigner, {
targetImplAddress: Deployment__OptimistInviterImpl.address,
targetProxyOwnerAddress: l2ProxyOwnerAddress,
postUpgradeCallCalldata: initializeCalldata,
})
const Deployment__AttestationStation = await hre.deployments.get(
'AttestationStationProxy'
)
await assert(
getAddress(
await Proxy.connect(ethers.constants.AddressZero).callStatic.admin()
) === getAddress(l2ProxyOwnerAddress)
)
await assertContractVariable(OptimistInviter, 'version', '1.0.0')
await assertContractVariable(
OptimistInviter,
'INVITE_GRANTER',
deployConfig.optimistInviterInviteGranter
)
await assertContractVariable(
OptimistInviter,
'ATTESTATION_STATION',
Deployment__AttestationStation.address
)
await assertContractVariable(OptimistInviter, 'EIP712_VERSION', '1.0.0')
}
deployFn.tags = ['OptimistInviterProxy', 'OptimistEnvironment']
deployFn.dependencies = ['AttestationStationProxy', 'OptimistInviterImpl']
export default deployFn
/* Imports: External */
import { DeployFunction } from 'hardhat-deploy/dist/types'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import '@eth-optimism/hardhat-deploy-config'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { assertContractVariable } from '@eth-optimism/contracts-bedrock/src/deploy-utils'
import { utils } from 'ethers'
import { setupProxyContract } from '../../src/helpers/setupProxyContract'
import type { DeployConfig } from '../../src'
const { getAddress } = utils
const deployFn: DeployFunction = async (hre: HardhatRuntimeEnvironment) => {
const deployConfig = hre.deployConfig as DeployConfig
const { deployer } = await hre.getNamedAccounts()
const ddd = deployConfig.ddd
if (getAddress(deployer) !== getAddress(ddd)) {
throw new Error('Must deploy with the ddd')
}
const Deployment__OptimistImpl = await hre.deployments.get('Optimist')
console.log(`Deploying OptimistProxy with ${deployer}`)
const { deploy } = await hre.deployments.deterministic('OptimistProxy', {
salt: hre.ethers.utils.solidityKeccak256(['string'], ['OptimistProxy']),
contract: 'Proxy',
from: deployer,
args: [deployer],
log: true,
})
await deploy()
const Deployment__OptimistProxy = await hre.deployments.get('OptimistProxy')
console.log(`OptimistProxy deployed to ${Deployment__OptimistProxy.address}`)
const Proxy = await hre.ethers.getContractAt(
'Proxy',
Deployment__OptimistProxy.address
)
const Optimist = await hre.ethers.getContractAt(
'Optimist',
Deployment__OptimistProxy.address
)
// ethers.Signer for the ddd. Should be the current owner of the Proxy.
const dddSigner = await hre.ethers.provider.getSigner(deployer)
// intended admin of the Proxy
const l2ProxyOwnerAddress = deployConfig.l2ProxyOwnerAddress
// Create the calldata for the call to `initialize()`
const name = deployConfig.optimistName
const symbol = deployConfig.optimistSymbol
const initializeCalldata = Optimist.interface.encodeFunctionData(
'initialize',
[name, symbol]
)
// setup the Proxy contract with correct implementation and admin, and initialize atomically
await setupProxyContract(Proxy, dddSigner, {
targetImplAddress: Deployment__OptimistImpl.address,
targetProxyOwnerAddress: l2ProxyOwnerAddress,
postUpgradeCallCalldata: initializeCalldata,
})
const Deployment__AttestationStationProxy = await hre.deployments.get(
'AttestationStationProxy'
)
const Deployment__OptimistAllowlistProxy = await hre.deployments.get(
'OptimistAllowlistProxy'
)
await assertContractVariable(Proxy, 'admin', l2ProxyOwnerAddress)
await assertContractVariable(Optimist, 'name', deployConfig.optimistName)
await assertContractVariable(Optimist, 'version', '2.0.0')
await assertContractVariable(Optimist, 'symbol', deployConfig.optimistSymbol)
await assertContractVariable(
Optimist,
'BASE_URI_ATTESTOR',
deployConfig.optimistBaseUriAttestorAddress
)
await assertContractVariable(
Optimist,
'OPTIMIST_ALLOWLIST',
Deployment__OptimistAllowlistProxy.address
)
await assertContractVariable(
Optimist,
'ATTESTATION_STATION',
Deployment__AttestationStationProxy.address
)
}
deployFn.tags = ['OptimistProxy', 'OptimistEnvironment']
deployFn.dependencies = ['AttestationStationProxy', 'OptimistImpl']
export default deployFn
{
"language": "Solidity",
"sources": {
"contracts/testing/helpers/TestERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\n\ncontract TestERC20 is ERC20 {\n constructor() ERC20(\"TEST\", \"TST\", 18) {}\n\n function mint(address to, uint256 value) public {\n _mint(to, value);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n uint8 public immutable decimals;\n\n /*//////////////////////////////////////////////////////////////\n ERC20 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 public totalSupply;\n\n mapping(address => uint256) public balanceOf;\n\n mapping(address => mapping(address => uint256)) public allowance;\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal immutable INITIAL_CHAIN_ID;\n\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n mapping(address => uint256) public nonces;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals\n ) {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n INITIAL_CHAIN_ID = block.chainid;\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 amount) public virtual returns (bool) {\n allowance[msg.sender][spender] = amount;\n\n emit Approval(msg.sender, spender, amount);\n\n return true;\n }\n\n function transfer(address to, uint256 amount) public virtual returns (bool) {\n balanceOf[msg.sender] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(msg.sender, to, amount);\n\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual returns (bool) {\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n balanceOf[from] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual {\n require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n // Unchecked because the only math done is incrementing\n // the owner's nonce which cannot realistically overflow.\n unchecked {\n address recoveredAddress = ecrecover(\n keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(\n abi.encode(\n keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n ),\n owner,\n spender,\n value,\n nonces[owner]++,\n deadline\n )\n )\n )\n ),\n v,\n r,\n s\n );\n\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n allowance[recoveredAddress][spender] = value;\n }\n\n emit Approval(owner, spender, value);\n }\n\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n }\n\n function computeDomainSeparator() internal view virtual returns (bytes32) {\n return\n keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(name)),\n keccak256(\"1\"),\n block.chainid,\n address(this)\n )\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 amount) internal virtual {\n totalSupply += amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal virtual {\n balanceOf[from] -= amount;\n\n // Cannot underflow because a user's balance\n // will never be larger than the total supply.\n unchecked {\n totalSupply -= amount;\n }\n\n emit Transfer(from, address(0), amount);\n }\n}\n"
},
"contracts/universal/AssetReceiver.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\nimport { Transactor } from \"./Transactor.sol\";\n\n/**\n * @title AssetReceiver\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\n */\ncontract AssetReceiver is Transactor {\n /**\n * @notice Emitted when ETH is received by this address.\n *\n * @param from Address that sent ETH to this contract.\n * @param amount Amount of ETH received.\n */\n event ReceivedETH(address indexed from, uint256 amount);\n\n /**\n * @notice Emitted when ETH is withdrawn from this address.\n *\n * @param withdrawer Address that triggered the withdrawal.\n * @param recipient Address that received the withdrawal.\n * @param amount ETH amount withdrawn.\n */\n event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\n\n /**\n * @notice Emitted when ERC20 tokens are withdrawn from this address.\n *\n * @param withdrawer Address that triggered the withdrawal.\n * @param recipient Address that received the withdrawal.\n * @param asset Address of the token being withdrawn.\n * @param amount ERC20 amount withdrawn.\n */\n event WithdrewERC20(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 amount\n );\n\n /**\n * @notice Emitted when ERC20 tokens are withdrawn from this address.\n *\n * @param withdrawer Address that triggered the withdrawal.\n * @param recipient Address that received the withdrawal.\n * @param asset Address of the token being withdrawn.\n * @param id Token ID being withdrawn.\n */\n event WithdrewERC721(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 id\n );\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Transactor(_owner) {}\n\n /**\n * @notice Make sure we can receive ETH.\n */\n receive() external payable {\n emit ReceivedETH(msg.sender, msg.value);\n }\n\n /**\n * @notice Withdraws full ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n */\n function withdrawETH(address payable _to) external onlyOwner {\n withdrawETH(_to, address(this).balance);\n }\n\n /**\n * @notice Withdraws partial ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n * @param _amount Amount of ETH to withdraw.\n */\n function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\n // slither-disable-next-line reentrancy-unlimited-gas\n (bool success, ) = _to.call{ value: _amount }(\"\");\n emit WithdrewETH(msg.sender, _to, _amount);\n }\n\n /**\n * @notice Withdraws full ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n */\n function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\n withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\n }\n\n /**\n * @notice Withdraws partial ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n * @param _amount Amount of ERC20 to withdraw.\n */\n function withdrawERC20(\n ERC20 _asset,\n address _to,\n uint256 _amount\n ) public onlyOwner {\n // slither-disable-next-line unchecked-transfer\n _asset.transfer(_to, _amount);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\n }\n\n /**\n * @notice Withdraws ERC721 token to the recipient.\n *\n * @param _asset ERC721 token to withdraw.\n * @param _to Address to receive the ERC721 token.\n * @param _id Token ID of the ERC721 token to withdraw.\n */\n function withdrawERC721(\n ERC721 _asset,\n address _to,\n uint256 _id\n ) external onlyOwner {\n _asset.transferFrom(address(this), _to, _id);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) internal _ownerOf;\n\n mapping(address => uint256) internal _balanceOf;\n\n function ownerOf(uint256 id) public view virtual returns (address owner) {\n require((owner = _ownerOf[id]) != address(0), \"NOT_MINTED\");\n }\n\n function balanceOf(address owner) public view virtual returns (uint256) {\n require(owner != address(0), \"ZERO_ADDRESS\");\n\n return _balanceOf[owner];\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) public getApproved;\n\n mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 id) public virtual {\n address owner = _ownerOf[id];\n\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n getApproved[id] = spender;\n\n emit Approval(owner, spender, id);\n }\n\n function setApprovalForAll(address operator, bool approved) public virtual {\n isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n require(from == _ownerOf[id], \"WRONG_FROM\");\n\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(\n msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\n \"NOT_AUTHORIZED\"\n );\n\n // Underflow of the sender's balance is impossible because we check for\n // ownership above and the recipient's balance can't realistically overflow.\n unchecked {\n _balanceOf[from]--;\n\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n delete getApproved[id];\n\n emit Transfer(from, to, id);\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n bytes calldata data\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 id) internal virtual {\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(_ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n // Counter overflow is incredibly unrealistic.\n unchecked {\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n emit Transfer(address(0), to, id);\n }\n\n function _burn(uint256 id) internal virtual {\n address owner = _ownerOf[id];\n\n require(owner != address(0), \"NOT_MINTED\");\n\n // Ownership check above ensures no underflow.\n unchecked {\n _balanceOf[owner]--;\n }\n\n delete _ownerOf[id];\n\n delete getApproved[id];\n\n emit Transfer(owner, address(0), id);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL SAFE MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _safeMint(address to, uint256 id) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _safeMint(\n address to,\n uint256 id,\n bytes memory data\n ) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721TokenReceiver {\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external virtual returns (bytes4) {\n return ERC721TokenReceiver.onERC721Received.selector;\n }\n}\n"
},
"contracts/universal/Transactor.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Owned } from \"@rari-capital/solmate/src/auth/Owned.sol\";\n\n/**\n * @title Transactor\n * @notice Transactor is a minimal contract that can send transactions.\n */\ncontract Transactor is Owned {\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Owned(_owner) {}\n\n /**\n * Sends a CALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _value ETH value to send with the call.\n *\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function CALL(\n address _target,\n bytes memory _data,\n uint256 _value\n ) external payable onlyOwner returns (bool, bytes memory) {\n return _target.call{ value: _value }(_data);\n }\n\n /**\n * Sends a DELEGATECALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n *\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function DELEGATECALL(address _target, bytes memory _data)\n external\n payable\n onlyOwner\n returns (bool, bytes memory)\n {\n // slither-disable-next-line controlled-delegatecall\n return _target.delegatecall(_data);\n }\n}\n"
},
"@rari-capital/solmate/src/auth/Owned.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event OwnerUpdated(address indexed user, address indexed newOwner);\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP STORAGE\n //////////////////////////////////////////////////////////////*/\n\n address public owner;\n\n modifier onlyOwner() virtual {\n require(msg.sender == owner, \"UNAUTHORIZED\");\n\n _;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address _owner) {\n owner = _owner;\n\n emit OwnerUpdated(address(0), _owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function setOwner(address newOwner) public virtual onlyOwner {\n owner = newOwner;\n\n emit OwnerUpdated(msg.sender, newOwner);\n }\n}\n"
},
"contracts/universal/drippie/Drippie.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { AssetReceiver } from \"../AssetReceiver.sol\";\nimport { IDripCheck } from \"./IDripCheck.sol\";\n\n/**\n * @title Drippie\n * @notice Drippie is a system for managing automated contract interactions. A specific interaction\n * is called a \"drip\" and can be executed according to some condition (called a dripcheck)\n * and an execution interval. Drips cannot be executed faster than the execution interval.\n * Drips can trigger arbitrary contract calls where the calling contract is this contract\n * address. Drips can also send ETH value, which makes them ideal for keeping addresses\n * sufficiently funded with ETH. Drippie is designed to be connected with smart contract\n * automation services so that drips can be executed automatically. However, Drippie is\n * specifically designed to be separated from these services so that trust assumptions are\n * better compartmentalized.\n */\ncontract Drippie is AssetReceiver {\n /**\n * @notice Enum representing different status options for a given drip.\n *\n * @custom:value NONE Drip does not exist.\n * @custom:value PAUSED Drip is paused and cannot be executed until reactivated.\n * @custom:value ACTIVE Drip is active and can be executed.\n * @custom:value ARCHIVED Drip is archived and can no longer be executed or reactivated.\n */\n enum DripStatus {\n NONE,\n PAUSED,\n ACTIVE,\n ARCHIVED\n }\n\n /**\n * @notice Represents a drip action.\n */\n struct DripAction {\n address payable target;\n bytes data;\n uint256 value;\n }\n\n /**\n * @notice Represents the configuration for a given drip.\n */\n struct DripConfig {\n bool reentrant;\n uint256 interval;\n IDripCheck dripcheck;\n bytes checkparams;\n DripAction[] actions;\n }\n\n /**\n * @notice Represents the state of an active drip.\n */\n struct DripState {\n DripStatus status;\n DripConfig config;\n uint256 last;\n uint256 count;\n }\n\n /**\n * @notice Emitted when a new drip is created.\n *\n * @param nameref Indexed name parameter (hashed).\n * @param name Unindexed name parameter (unhashed).\n * @param config Config for the created drip.\n */\n event DripCreated(\n // Emit name twice because indexed version is hashed.\n string indexed nameref,\n string name,\n DripConfig config\n );\n\n /**\n * @notice Emitted when a drip status is updated.\n *\n * @param nameref Indexed name parameter (hashed).\n * @param name Unindexed name parameter (unhashed).\n * @param status New drip status.\n */\n event DripStatusUpdated(\n // Emit name twice because indexed version is hashed.\n string indexed nameref,\n string name,\n DripStatus status\n );\n\n /**\n * @notice Emitted when a drip is executed.\n *\n * @param nameref Indexed name parameter (hashed).\n * @param name Unindexed name parameter (unhashed).\n * @param executor Address that executed the drip.\n * @param timestamp Time when the drip was executed.\n */\n event DripExecuted(\n // Emit name twice because indexed version is hashed.\n string indexed nameref,\n string name,\n address executor,\n uint256 timestamp\n );\n\n /**\n * @notice Maps from drip names to drip states.\n */\n mapping(string => DripState) public drips;\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) AssetReceiver(_owner) {}\n\n /**\n * @notice Creates a new drip with the given name and configuration. Once created, drips cannot\n * be modified in any way (this is a security measure). If you want to update a drip,\n * simply pause (and potentially archive) the existing drip and create a new one.\n *\n * @param _name Name of the drip.\n * @param _config Configuration for the drip.\n */\n function create(string calldata _name, DripConfig calldata _config) external onlyOwner {\n // Make sure this drip doesn't already exist. We *must* guarantee that no other function\n // will ever set the status of a drip back to NONE after it's been created. This is why\n // archival is a separate status.\n require(\n drips[_name].status == DripStatus.NONE,\n \"Drippie: drip with that name already exists\"\n );\n\n // Validate the drip interval, only allowing an interval of zero if the drip has explicitly\n // been marked as reentrant. Prevents client-side bugs making a drip infinitely executable\n // within the same block (of course, restricted by gas limits).\n if (_config.reentrant) {\n require(\n _config.interval == 0,\n \"Drippie: if allowing reentrant drip, must set interval to zero\"\n );\n } else {\n require(\n _config.interval > 0,\n \"Drippie: interval must be greater than zero if drip is not reentrant\"\n );\n }\n\n // We initialize this way because Solidity won't let us copy arrays into storage yet.\n DripState storage state = drips[_name];\n state.status = DripStatus.PAUSED;\n state.config.reentrant = _config.reentrant;\n state.config.interval = _config.interval;\n state.config.dripcheck = _config.dripcheck;\n state.config.checkparams = _config.checkparams;\n\n // Solidity doesn't let us copy arrays into storage, so we push each array one by one.\n for (uint256 i = 0; i < _config.actions.length; i++) {\n state.config.actions.push(_config.actions[i]);\n }\n\n // Tell the world!\n emit DripCreated(_name, _name, _config);\n }\n\n /**\n * @notice Sets the status for a given drip. The behavior of this function depends on the\n * status that the user is trying to set. A drip can always move between ACTIVE and\n * PAUSED, but it can never move back to NONE and once ARCHIVED, it can never move back\n * to ACTIVE or PAUSED.\n *\n * @param _name Name of the drip to update.\n * @param _status New drip status.\n */\n function status(string calldata _name, DripStatus _status) external onlyOwner {\n // Make sure we can never set drip status back to NONE. A simple security measure to\n // prevent accidental overwrites if this code is ever updated down the line.\n require(\n _status != DripStatus.NONE,\n \"Drippie: drip status can never be set back to NONE after creation\"\n );\n\n // Load the drip status once to avoid unnecessary SLOADs.\n DripStatus curr = drips[_name].status;\n\n // Make sure the drip in question actually exists. Not strictly necessary but there doesn't\n // seem to be any clear reason why you would want to do this, and it may save some gas in\n // the case of a front-end bug.\n require(\n curr != DripStatus.NONE,\n \"Drippie: drip with that name does not exist and cannot be updated\"\n );\n\n // Once a drip has been archived, it cannot be un-archived. This is, after all, the entire\n // point of archiving a drip.\n require(\n curr != DripStatus.ARCHIVED,\n \"Drippie: drip with that name has been archived and cannot be updated\"\n );\n\n // Although not strictly necessary, we make sure that the status here is actually changing.\n // This may save the client some gas if there's a front-end bug and the user accidentally\n // tries to \"change\" the status to the same value as before.\n require(\n curr != _status,\n \"Drippie: cannot set drip status to the same status as its current status\"\n );\n\n // If the user is trying to archive this drip, make sure the drip has been paused. We do\n // not allow users to archive active drips so that the effects of this action are more\n // abundantly clear.\n if (_status == DripStatus.ARCHIVED) {\n require(\n curr == DripStatus.PAUSED,\n \"Drippie: drip must first be paused before being archived\"\n );\n }\n\n // If we made it here then we can safely update the status.\n drips[_name].status = _status;\n emit DripStatusUpdated(_name, _name, _status);\n }\n\n /**\n * @notice Checks if a given drip is executable.\n *\n * @param _name Drip to check.\n *\n * @return True if the drip is executable, reverts otherwise.\n */\n function executable(string calldata _name) public view returns (bool) {\n DripState storage state = drips[_name];\n\n // Only allow active drips to be executed, an obvious security measure.\n require(\n state.status == DripStatus.ACTIVE,\n \"Drippie: selected drip does not exist or is not currently active\"\n );\n\n // Don't drip if the drip interval has not yet elapsed since the last time we dripped. This\n // is a safety measure that prevents a malicious recipient from, e.g., spending all of\n // their funds and repeatedly requesting new drips. Limits the potential impact of a\n // compromised recipient to just a single drip interval, after which the drip can be paused\n // by the owner address.\n require(\n state.last + state.config.interval <= block.timestamp,\n \"Drippie: drip interval has not elapsed since last drip\"\n );\n\n // Make sure we're allowed to execute this drip.\n require(\n state.config.dripcheck.check(state.config.checkparams),\n \"Drippie: dripcheck failed so drip is not yet ready to be triggered\"\n );\n\n // Alright, we're good to execute.\n return true;\n }\n\n /**\n * @notice Triggers a drip. This function is deliberately left as a public function because the\n * assumption being made here is that setting the drip to ACTIVE is an affirmative\n * signal that the drip should be executable according to the drip parameters, drip\n * check, and drip interval. Note that drip parameters are read entirely from the state\n * and are not supplied as user input, so there should not be any way for a\n * non-authorized user to influence the behavior of the drip. Note that the drip check\n * is executed only **once** at the beginning of the call to the drip function and will\n * not be executed again between the drip actions within this call.\n *\n * @param _name Name of the drip to trigger.\n */\n function drip(string calldata _name) external {\n DripState storage state = drips[_name];\n\n // Make sure the drip can be executed. Since executable reverts if the drip is not ready to\n // be executed, we don't need to do an assertion that the returned value is true.\n executable(_name);\n\n // Update the last execution time for this drip before the call. Note that it's entirely\n // possible for a drip to be executed multiple times per block or even multiple times\n // within the same transaction (via re-entrancy) if the drip interval is set to zero. Users\n // should set a drip interval of 1 if they'd like the drip to be executed only once per\n // block (since this will then prevent re-entrancy).\n state.last = block.timestamp;\n\n // Update the number of times this drip has been executed. Although this increases the cost\n // of using Drippie, it slightly simplifies the client-side by not having to worry about\n // counting drips via events. Useful for monitoring the rate of drip execution.\n state.count++;\n\n // Execute each action in the drip. We allow drips to have multiple actions because there\n // are scenarios in which a contract must do multiple things atomically. For example, the\n // contract may need to withdraw ETH from one account and then deposit that ETH into\n // another account within the same transaction.\n uint256 len = state.config.actions.length;\n for (uint256 i = 0; i < len; i++) {\n // Must be marked as \"storage\" because copying structs into memory is not yet supported\n // by Solidity. Won't significantly reduce gas costs but at least makes it easier to\n // read what the rest of this section is doing.\n DripAction storage action = state.config.actions[i];\n\n // Actually execute the action. We could use ExcessivelySafeCall here but not strictly\n // necessary (worst case, a drip gets bricked IFF the target is malicious, doubt this\n // will ever happen in practice). Could save a marginal amount of gas to ignore the\n // returndata.\n // slither-disable-next-line calls-loop\n (bool success, ) = action.target.call{ value: action.value }(action.data);\n\n // Generally should not happen, but could if there's a misconfiguration (e.g., passing\n // the wrong data to the target contract), the recipient is not payable, or\n // insufficient gas was supplied to this transaction. We revert so the drip can be\n // fixed and triggered again later. Means we cannot emit an event to alert of the\n // failure, but can reasonably be detected by off-chain services even without an event.\n // Note that this forces the drip executor to supply sufficient gas to the call\n // (assuming there is some sufficient gas limit that exists, otherwise the drip will\n // not execute).\n require(\n success,\n \"Drippie: drip was unsuccessful, please check your configuration for mistakes\"\n );\n }\n\n emit DripExecuted(_name, _name, msg.sender, block.timestamp);\n }\n}\n"
},
"contracts/universal/drippie/IDripCheck.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IDripCheck {\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\n // possible to easily encode parameters on the client side. Solidity does not support generics\n // so it's not possible to do this with explicit typing.\n\n /**\n * @notice Checks whether a drip should be executable.\n *\n * @param _params Encoded parameters for the drip check.\n *\n * @return Whether the drip should be executed.\n */\n function check(bytes memory _params) external view returns (bool);\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckTrue.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckTrue\n * @notice DripCheck that always returns true.\n */\ncontract CheckTrue is IDripCheck {\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory) external pure returns (bool) {\n return true;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\ninterface IGelatoTreasury {\n function userTokenBalance(address _user, address _token) external view returns (uint256);\n}\n\n/**\n * @title CheckGelatoLow\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\n */\ncontract CheckGelatoLow is IDripCheck {\n struct Params {\n address treasury;\n uint256 threshold;\n address recipient;\n }\n\n /**\n * @notice External event used to help client-side tooling encode parameters.\n *\n * @param params Parameters to encode.\n */\n event _EventToExposeStructInABI__Params(Params params);\n\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check GelatoTreasury ETH balance is below threshold.\n return\n IGelatoTreasury(params.treasury).userTokenBalance(\n params.recipient,\n // Gelato represents ETH as 0xeeeee....eeeee\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\n ) < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceLow\n * @notice DripCheck for checking if an account's balance is below a given threshold.\n */\ncontract CheckBalanceLow is IDripCheck {\n struct Params {\n address target;\n uint256 threshold;\n }\n\n /**\n * @notice External event used to help client-side tooling encode parameters.\n *\n * @param params Parameters to encode.\n */\n event _EventToExposeStructInABI__Params(Params params);\n\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target ETH balance is below threshold.\n return params.target.balance < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceHigh\n * @notice DripCheck for checking if an account's balance is above a given threshold.\n */\ncontract CheckBalanceHigh is IDripCheck {\n struct Params {\n address target;\n uint256 threshold;\n }\n\n /**\n * @notice External event used to help client-side tooling encode parameters.\n *\n * @param params Parameters to encode.\n */\n event _EventToExposeStructInABI__Params(Params params);\n\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target balance is above threshold.\n return params.target.balance > params.threshold;\n }\n}\n"
},
"contracts/testing/helpers/TestERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\n\ncontract TestERC721 is ERC721 {\n constructor() ERC721(\"TEST\", \"TST\") {}\n\n function mint(address to, uint256 tokenId) public {\n _mint(to, tokenId);\n }\n\n function tokenURI(uint256) public pure virtual override returns (string memory) {}\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"address": "0xd5F62980C9d1bAa2A983bF16F8874A92F0050C48",
"abi": [
{
"anonymous": false,
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "uint256",
"name": "threshold",
"type": "uint256"
}
],
"indexed": false,
"internalType": "struct CheckBalanceHigh.Params",
"name": "params",
"type": "tuple"
}
],
"name": "_EventToExposeStructInABI__Params",
"type": "event"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "_params",
"type": "bytes"
}
],
"name": "check",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
],
"args": [],
"numDeployments": 1,
"solcInputHash": "b09909e91a3ff9823ceba49a3a845230",
"metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"struct CheckBalanceHigh.Params\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"_EventToExposeStructInABI__Params\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_params\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"CheckBalanceHigh\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"DripCheck for checking if an account's balance is above a given threshold.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol\":\"CheckBalanceHigh\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x73db6ada63ed1f0eba24efd36099139e66908aa45c79c0d1defe2a59a9e9eb9d\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\n/**\\n * @title CheckBalanceHigh\\n * @notice DripCheck for checking if an account's balance is above a given threshold.\\n */\\ncontract CheckBalanceHigh is IDripCheck {\\n event _EventToExposeStructInABI__Params(Params params);\\n struct Params {\\n address target;\\n uint256 threshold;\\n }\\n\\n function check(bytes memory _params) external view returns (bool) {\\n Params memory params = abi.decode(_params, (Params));\\n\\n // Check target balance is above threshold.\\n return params.target.balance > params.threshold;\\n }\\n}\\n\",\"keccak256\":\"0x517f69b75b62b7b74d3d4fceb45ecacb9cf1d68b62a8517e2985a6e0da0a7575\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b50610239806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631119392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea2646970667358221220c3948eadf9cbb80bb928bc392291d583593cefbaff6536ec1485a7602e7f6b7f64736f6c63430008090033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631119392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea2646970667358221220c3948eadf9cbb80bb928bc392291d583593cefbaff6536ec1485a7602e7f6b7f64736f6c63430008090033",
"devdoc": {
"kind": "dev",
"methods": {},
"title": "CheckBalanceHigh",
"version": 1
},
"userdoc": {
"kind": "user",
"methods": {},
"notice": "DripCheck for checking if an account's balance is above a given threshold.",
"version": 1
},
"storageLayout": {
"storage": [],
"types": null
}
}
\ No newline at end of file
{
"address": "0x00B1D6438A4E7E3733Bd9fCe4A068b07A0E47620",
"abi": [
{
"anonymous": false,
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "target",
"type": "address"
},
{
"internalType": "uint256",
"name": "threshold",
"type": "uint256"
}
],
"indexed": false,
"internalType": "struct CheckBalanceLow.Params",
"name": "params",
"type": "tuple"
}
],
"name": "_EventToExposeStructInABI__Params",
"type": "event"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "_params",
"type": "bytes"
}
],
"name": "check",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
],
"transactionHash": "0x65f0d04160b33d020aed8bfc4207f169d230549d8cff494f600b104fe0e689a1",
"receipt": {
"to": "0x4e59b44847b379578588920cA78FbF26c0B4956C",
"from": "0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5",
"contractAddress": null,
"transactionIndex": 81,
"gasUsed": "176640",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"blockHash": "0xb1ddf0d044777738b0a1e53a28129e5d58076dbaa9b190843b76354706d8880b",
"transactionHash": "0x65f0d04160b33d020aed8bfc4207f169d230549d8cff494f600b104fe0e689a1",
"logs": [],
"blockNumber": 14981100,
"cumulativeGasUsed": "5262258",
"status": 1,
"byzantium": true
},
"args": [],
"numDeployments": 1,
"solcInputHash": "b09909e91a3ff9823ceba49a3a845230",
"metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"target\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"}],\"indexed\":false,\"internalType\":\"struct CheckBalanceLow.Params\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"_EventToExposeStructInABI__Params\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_params\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"CheckBalanceLow\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"DripCheck for checking if an account's balance is below a given threshold.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol\":\"CheckBalanceLow\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x73db6ada63ed1f0eba24efd36099139e66908aa45c79c0d1defe2a59a9e9eb9d\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\n/**\\n * @title CheckBalanceLow\\n * @notice DripCheck for checking if an account's balance is below a given threshold.\\n */\\ncontract CheckBalanceLow is IDripCheck {\\n event _EventToExposeStructInABI__Params(Params params);\\n struct Params {\\n address target;\\n uint256 threshold;\\n }\\n\\n function check(bytes memory _params) external view returns (bool) {\\n Params memory params = abi.decode(_params, (Params));\\n\\n // Check target ETH balance is below threshold.\\n return params.target.balance < params.threshold;\\n }\\n}\\n\",\"keccak256\":\"0xd6d8e6abcc1428666132e9d8140243fff23c564b6474927e18f30fe078801842\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b50610239806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea264697066735822122075d8f6816a6709f5b54613834c7be6979cb3af4abf6a1d38244135be431d562b64736f6c63430008090033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e3660046100c3565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610192565b6020810151905173ffffffffffffffffffffffffffffffffffffffff1631109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6000602082840312156100d557600080fd5b813567ffffffffffffffff808211156100ed57600080fd5b818401915084601f83011261010157600080fd5b81358181111561011357610113610094565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561015957610159610094565b8160405282815287602084870101111561017257600080fd5b826020860160208301376000928101602001929092525095945050505050565b6000604082840312156101a457600080fd5b6040516040810181811067ffffffffffffffff821117156101c7576101c7610094565b604052825173ffffffffffffffffffffffffffffffffffffffff811681146101ee57600080fd5b8152602092830151928101929092525091905056fea264697066735822122075d8f6816a6709f5b54613834c7be6979cb3af4abf6a1d38244135be431d562b64736f6c63430008090033",
"devdoc": {
"kind": "dev",
"methods": {},
"title": "CheckBalanceLow",
"version": 1
},
"userdoc": {
"kind": "user",
"methods": {},
"notice": "DripCheck for checking if an account's balance is below a given threshold.",
"version": 1
},
"storageLayout": {
"storage": [],
"types": null
}
}
\ No newline at end of file
{
"address": "0x81d70959f29872A9e597a54658A93962F7D9B597",
"abi": [
{
"anonymous": false,
"inputs": [
{
"components": [
{
"internalType": "address",
"name": "treasury",
"type": "address"
},
{
"internalType": "uint256",
"name": "threshold",
"type": "uint256"
},
{
"internalType": "address",
"name": "recipient",
"type": "address"
}
],
"indexed": false,
"internalType": "struct CheckGelatoLow.Params",
"name": "params",
"type": "tuple"
}
],
"name": "_EventToExposeStructInABI__Params",
"type": "event"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "_params",
"type": "bytes"
}
],
"name": "check",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "view",
"type": "function"
}
],
"transactionHash": "0x4f3db725a79a177062c8ddbbedb005a96ecb8eab6e71c4172c1b37fa1c708688",
"receipt": {
"to": "0x4e59b44847b379578588920cA78FbF26c0B4956C",
"from": "0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5",
"contractAddress": null,
"transactionIndex": 53,
"gasUsed": "225248",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"blockHash": "0xae292ed733027c5232a5775cd788ce31394cf4e7a068b7f2edbf8bd142e40d8f",
"transactionHash": "0x4f3db725a79a177062c8ddbbedb005a96ecb8eab6e71c4172c1b37fa1c708688",
"logs": [],
"blockNumber": 14981104,
"cumulativeGasUsed": "5063510",
"status": 1,
"byzantium": true
},
"args": [],
"numDeployments": 1,
"solcInputHash": "b09909e91a3ff9823ceba49a3a845230",
"metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"anonymous\":false,\"inputs\":[{\"components\":[{\"internalType\":\"address\",\"name\":\"treasury\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"threshold\",\"type\":\"uint256\"},{\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"}],\"indexed\":false,\"internalType\":\"struct CheckGelatoLow.Params\",\"name\":\"params\",\"type\":\"tuple\"}],\"name\":\"_EventToExposeStructInABI__Params\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_params\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"CheckGelatoLow\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"DripCheck for checking if an account's Gelato ETH balance is below some threshold.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol\":\"CheckGelatoLow\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x73db6ada63ed1f0eba24efd36099139e66908aa45c79c0d1defe2a59a9e9eb9d\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\ninterface IGelatoTreasury {\\n function userTokenBalance(address _user, address _token) external view returns (uint256);\\n}\\n\\n/**\\n * @title CheckGelatoLow\\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\\n */\\ncontract CheckGelatoLow is IDripCheck {\\n event _EventToExposeStructInABI__Params(Params params);\\n struct Params {\\n address treasury;\\n uint256 threshold;\\n address recipient;\\n }\\n\\n function check(bytes memory _params) external view returns (bool) {\\n Params memory params = abi.decode(_params, (Params));\\n\\n // Check GelatoTreasury ETH balance is below threshold.\\n return\\n IGelatoTreasury(params.treasury).userTokenBalance(\\n params.recipient,\\n // Gelato represents ETH as 0xeeeee....eeeee\\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\\n ) < params.threshold;\\n }\\n}\\n\",\"keccak256\":\"0x8d936bc5e037a1b05225f2cd208ef6899b0d29cd3b91c73e5c16762eb242e5ef\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b5061031b806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e36600461016f565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610267565b6020810151815160408084015190517fb47064c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6024820152939450919291169063b47064c89060440160206040518083038186803b15801561010057600080fd5b505afa158015610114573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061013891906102cc565b109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561018157600080fd5b813567ffffffffffffffff8082111561019957600080fd5b818401915084601f8301126101ad57600080fd5b8135818111156101bf576101bf610140565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561020557610205610140565b8160405282815287602084870101111561021e57600080fd5b826020860160208301376000928101602001929092525095945050505050565b805173ffffffffffffffffffffffffffffffffffffffff8116811461026257600080fd5b919050565b60006060828403121561027957600080fd5b6040516060810181811067ffffffffffffffff8211171561029c5761029c610140565b6040526102a88361023e565b8152602083015160208201526102c06040840161023e565b60408201529392505050565b6000602082840312156102de57600080fd5b505191905056fea2646970667358221220e4e865f160af7ad5bd6e586c93c567a5f9a5ee5a652397683119d14d6f5e658464736f6c63430008090033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004361003e36600461016f565b610057565b604051901515815260200160405180910390f35b6000808280602001905181019061006e9190610267565b6020810151815160408084015190517fb47064c800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff918216600482015273eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee6024820152939450919291169063b47064c89060440160206040518083038186803b15801561010057600080fd5b505afa158015610114573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061013891906102cc565b109392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561018157600080fd5b813567ffffffffffffffff8082111561019957600080fd5b818401915084601f8301126101ad57600080fd5b8135818111156101bf576101bf610140565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561020557610205610140565b8160405282815287602084870101111561021e57600080fd5b826020860160208301376000928101602001929092525095945050505050565b805173ffffffffffffffffffffffffffffffffffffffff8116811461026257600080fd5b919050565b60006060828403121561027957600080fd5b6040516060810181811067ffffffffffffffff8211171561029c5761029c610140565b6040526102a88361023e565b8152602083015160208201526102c06040840161023e565b60408201529392505050565b6000602082840312156102de57600080fd5b505191905056fea2646970667358221220e4e865f160af7ad5bd6e586c93c567a5f9a5ee5a652397683119d14d6f5e658464736f6c63430008090033",
"devdoc": {
"kind": "dev",
"methods": {},
"title": "CheckGelatoLow",
"version": 1
},
"userdoc": {
"kind": "user",
"methods": {},
"notice": "DripCheck for checking if an account's Gelato ETH balance is below some threshold.",
"version": 1
},
"storageLayout": {
"storage": [],
"types": null
}
}
\ No newline at end of file
{
"address": "0x7e2B28af043c347C18fc37f62B5D001df6BFa26c",
"abi": [
{
"inputs": [
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"name": "check",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
}
],
"stateMutability": "pure",
"type": "function"
}
],
"transactionHash": "0x02af8af4f6eda0944e437af66082a71b3a0c9c52f3ab2ac4e4929538f94d9411",
"receipt": {
"to": "0x4e59b44847b379578588920cA78FbF26c0B4956C",
"from": "0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5",
"contractAddress": null,
"transactionIndex": 6,
"gasUsed": "139230",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
"blockHash": "0xbf599dc7b5468b1291bd41db9290db892c3e883c7f24cfa123f0ce4fa19d8bf3",
"transactionHash": "0x02af8af4f6eda0944e437af66082a71b3a0c9c52f3ab2ac4e4929538f94d9411",
"logs": [],
"blockNumber": 14981108,
"cumulativeGasUsed": "630300",
"status": 1,
"byzantium": true
},
"args": [],
"numDeployments": 1,
"solcInputHash": "b09909e91a3ff9823ceba49a3a845230",
"metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"name\":\"check\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"}],\"stateMutability\":\"pure\",\"type\":\"function\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{},\"title\":\"CheckTrue\",\"version\":1},\"userdoc\":{\"kind\":\"user\",\"methods\":{},\"notice\":\"DripCheck that always returns true.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/drippie/dripchecks/CheckTrue.sol\":\"CheckTrue\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"contracts/universal/drippie/IDripCheck.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\ninterface IDripCheck {\\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\\n // possible to easily encode parameters on the client side. Solidity does not support generics\\n // so it's not possible to do this with explicit typing.\\n\\n function check(bytes memory _params) external view returns (bool);\\n}\\n\",\"keccak256\":\"0x73db6ada63ed1f0eba24efd36099139e66908aa45c79c0d1defe2a59a9e9eb9d\",\"license\":\"MIT\"},\"contracts/universal/drippie/dripchecks/CheckTrue.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { IDripCheck } from \\\"../IDripCheck.sol\\\";\\n\\n/**\\n * @title CheckTrue\\n * @notice DripCheck that always returns true.\\n */\\ncontract CheckTrue is IDripCheck {\\n function check(bytes memory) external pure returns (bool) {\\n return true;\\n }\\n}\\n\",\"keccak256\":\"0x2ed60821a4302130b567da45f15dce5a7c41e5d5b016c32ec09c92d4fb5ba6e6\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b5061018c806100206000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004461003e366004610087565b50600190565b604051901515815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561009957600080fd5b813567ffffffffffffffff808211156100b157600080fd5b818401915084601f8301126100c557600080fd5b8135818111156100d7576100d7610058565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561011d5761011d610058565b8160405282815287602084870101111561013657600080fd5b82602086016020830137600092810160200192909252509594505050505056fea26469706673582212207179cc803626c6d5a28bb5725d572d164ec9b64d4f37f10f220761ee045840fc64736f6c63430008090033",
"deployedBytecode": "0x608060405234801561001057600080fd5b506004361061002b5760003560e01c8063c64b3bb514610030575b600080fd5b61004461003e366004610087565b50600190565b604051901515815260200160405180910390f35b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b60006020828403121561009957600080fd5b813567ffffffffffffffff808211156100b157600080fd5b818401915084601f8301126100c557600080fd5b8135818111156100d7576100d7610058565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190838211818310171561011d5761011d610058565b8160405282815287602084870101111561013657600080fd5b82602086016020830137600092810160200192909252509594505050505056fea26469706673582212207179cc803626c6d5a28bb5725d572d164ec9b64d4f37f10f220761ee045840fc64736f6c63430008090033",
"devdoc": {
"kind": "dev",
"methods": {},
"title": "CheckTrue",
"version": 1
},
"userdoc": {
"kind": "user",
"methods": {},
"notice": "DripCheck that always returns true.",
"version": 1
},
"storageLayout": {
"storage": [],
"types": null
}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"address": "0x5a7749f83b81B301cAb5f48EB8516B986DAef23D",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "_admin",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": false,
"internalType": "address",
"name": "previousAdmin",
"type": "address"
},
{
"indexed": false,
"internalType": "address",
"name": "newAdmin",
"type": "address"
}
],
"name": "AdminChanged",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "implementation",
"type": "address"
}
],
"name": "Upgraded",
"type": "event"
},
{
"stateMutability": "payable",
"type": "fallback"
},
{
"inputs": [],
"name": "admin",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_admin",
"type": "address"
}
],
"name": "changeAdmin",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "implementation",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_implementation",
"type": "address"
}
],
"name": "upgradeTo",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_implementation",
"type": "address"
},
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
}
],
"name": "upgradeToAndCall",
"outputs": [
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
],
"transactionHash": "0x7583d011cf1593fb1ffc79b097b0a365192c87dfdccbf860e1ad3f1425a305ef",
"receipt": {
"to": null,
"from": "0x53A6eecC2dD4795Fcc68940ddc6B4d53Bd88Bd9E",
"contractAddress": "0x5a7749f83b81B301cAb5f48EB8516B986DAef23D",
"transactionIndex": 140,
"gasUsed": "532674",
"logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000800000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000800000000000000000000000000",
"blockHash": "0xa5c98ae09c1db0857551a9eaca6d88e1bff5f8103814795c0ed1e7863e16a6d5",
"transactionHash": "0x7583d011cf1593fb1ffc79b097b0a365192c87dfdccbf860e1ad3f1425a305ef",
"logs": [
{
"transactionIndex": 140,
"blockNumber": 15677422,
"transactionHash": "0x7583d011cf1593fb1ffc79b097b0a365192c87dfdccbf860e1ad3f1425a305ef",
"address": "0x5a7749f83b81B301cAb5f48EB8516B986DAef23D",
"topics": [
"0x7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f"
],
"data": "0x000000000000000000000000000000000000000000000000000000000000000000000000000000000000000053a6eecc2dd4795fcc68940ddc6b4d53bd88bd9e",
"logIndex": 251,
"blockHash": "0xa5c98ae09c1db0857551a9eaca6d88e1bff5f8103814795c0ed1e7863e16a6d5"
}
],
"blockNumber": 15677422,
"cumulativeGasUsed": "12586381",
"status": 1,
"byzantium": true
},
"args": [
"0x53A6eecC2dD4795Fcc68940ddc6B4d53Bd88Bd9E"
],
"numDeployments": 1,
"solcInputHash": "ab9b77493f35e63b7a63fb2fa8d618b4",
"metadata": "{\"compiler\":{\"version\":\"0.8.15+commit.e14f2714\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_admin\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":false,\"internalType\":\"address\",\"name\":\"previousAdmin\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"address\",\"name\":\"newAdmin\",\"type\":\"address\"}],\"name\":\"AdminChanged\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"implementation\",\"type\":\"address\"}],\"name\":\"Upgraded\",\"type\":\"event\"},{\"stateMutability\":\"payable\",\"type\":\"fallback\"},{\"inputs\":[],\"name\":\"admin\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_admin\",\"type\":\"address\"}],\"name\":\"changeAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"implementation\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"}],\"name\":\"upgradeTo\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_implementation\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"upgradeToAndCall\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"events\":{\"AdminChanged(address,address)\":{\"params\":{\"newAdmin\":\"The new owner of the contract\",\"previousAdmin\":\"The previous owner of the contract\"}},\"Upgraded(address)\":{\"params\":{\"implementation\":\"The address of the implementation contract\"}}},\"kind\":\"dev\",\"methods\":{\"admin()\":{\"returns\":{\"_0\":\"Owner address.\"}},\"changeAdmin(address)\":{\"params\":{\"_admin\":\"New owner of the proxy contract.\"}},\"constructor\":{\"params\":{\"_admin\":\"Address of the initial contract admin. Admin as the ability to access the transparent proxy interface.\"}},\"implementation()\":{\"returns\":{\"_0\":\"Implementation address.\"}},\"upgradeTo(address)\":{\"params\":{\"_implementation\":\"Address of the implementation contract.\"}},\"upgradeToAndCall(address,bytes)\":{\"params\":{\"_data\":\"Calldata to delegatecall the new implementation with.\",\"_implementation\":\"Address of the implementation contract.\"}}},\"title\":\"Proxy\",\"version\":1},\"userdoc\":{\"events\":{\"AdminChanged(address,address)\":{\"notice\":\"An event that is emitted each time the owner is upgraded. This event is part of the EIP-1967 specification.\"},\"Upgraded(address)\":{\"notice\":\"An event that is emitted each time the implementation is changed. This event is part of the EIP-1967 specification.\"}},\"kind\":\"user\",\"methods\":{\"admin()\":{\"notice\":\"Gets the owner of the proxy contract.\"},\"changeAdmin(address)\":{\"notice\":\"Changes the owner of the proxy contract. Only callable by the owner.\"},\"constructor\":{\"notice\":\"Sets the initial admin during contract deployment. Admin address is stored at the EIP-1967 admin storage slot so that accidental storage collision with the implementation is not possible.\"},\"implementation()\":{\"notice\":\"Queries the implementation address.\"},\"upgradeTo(address)\":{\"notice\":\"Set the implementation contract address. The code at the given address will execute when this contract is called.\"},\"upgradeToAndCall(address,bytes)\":{\"notice\":\"Set the implementation and call a function in a single transaction. Useful to ensure atomic execution of initialization-based upgrades.\"}},\"notice\":\"Proxy is a transparent proxy that passes through the call if the caller is the owner or if the caller is address(0), meaning that the call originated from an off-chain simulation.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"@eth-optimism/contracts-bedrock/contracts/universal/Proxy.sol\":\"Proxy\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"@eth-optimism/contracts-bedrock/contracts/universal/Proxy.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity 0.8.15;\\n\\n/**\\n * @title Proxy\\n * @notice Proxy is a transparent proxy that passes through the call if the caller is the owner or\\n * if the caller is address(0), meaning that the call originated from an off-chain\\n * simulation.\\n */\\ncontract Proxy {\\n /**\\n * @notice The storage slot that holds the address of the implementation.\\n * bytes32(uint256(keccak256('eip1967.proxy.implementation')) - 1)\\n */\\n bytes32 internal constant IMPLEMENTATION_KEY =\\n 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;\\n\\n /**\\n * @notice The storage slot that holds the address of the owner.\\n * bytes32(uint256(keccak256('eip1967.proxy.admin')) - 1)\\n */\\n bytes32 internal constant OWNER_KEY =\\n 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;\\n\\n /**\\n * @notice An event that is emitted each time the implementation is changed. This event is part\\n * of the EIP-1967 specification.\\n *\\n * @param implementation The address of the implementation contract\\n */\\n event Upgraded(address indexed implementation);\\n\\n /**\\n * @notice An event that is emitted each time the owner is upgraded. This event is part of the\\n * EIP-1967 specification.\\n *\\n * @param previousAdmin The previous owner of the contract\\n * @param newAdmin The new owner of the contract\\n */\\n event AdminChanged(address previousAdmin, address newAdmin);\\n\\n /**\\n * @notice A modifier that reverts if not called by the owner or by address(0) to allow\\n * eth_call to interact with this proxy without needing to use low-level storage\\n * inspection. We assume that nobody is able to trigger calls from address(0) during\\n * normal EVM execution.\\n */\\n modifier proxyCallIfNotAdmin() {\\n if (msg.sender == _getAdmin() || msg.sender == address(0)) {\\n _;\\n } else {\\n // This WILL halt the call frame on completion.\\n _doProxyCall();\\n }\\n }\\n\\n /**\\n * @notice Sets the initial admin during contract deployment. Admin address is stored at the\\n * EIP-1967 admin storage slot so that accidental storage collision with the\\n * implementation is not possible.\\n *\\n * @param _admin Address of the initial contract admin. Admin as the ability to access the\\n * transparent proxy interface.\\n */\\n constructor(address _admin) {\\n _changeAdmin(_admin);\\n }\\n\\n // slither-disable-next-line locked-ether\\n receive() external payable {\\n // Proxy call by default.\\n _doProxyCall();\\n }\\n\\n // slither-disable-next-line locked-ether\\n fallback() external payable {\\n // Proxy call by default.\\n _doProxyCall();\\n }\\n\\n /**\\n * @notice Set the implementation contract address. The code at the given address will execute\\n * when this contract is called.\\n *\\n * @param _implementation Address of the implementation contract.\\n */\\n function upgradeTo(address _implementation) external proxyCallIfNotAdmin {\\n _setImplementation(_implementation);\\n }\\n\\n /**\\n * @notice Set the implementation and call a function in a single transaction. Useful to ensure\\n * atomic execution of initialization-based upgrades.\\n *\\n * @param _implementation Address of the implementation contract.\\n * @param _data Calldata to delegatecall the new implementation with.\\n */\\n function upgradeToAndCall(address _implementation, bytes calldata _data)\\n external\\n payable\\n proxyCallIfNotAdmin\\n returns (bytes memory)\\n {\\n _setImplementation(_implementation);\\n (bool success, bytes memory returndata) = _implementation.delegatecall(_data);\\n require(success, \\\"Proxy: delegatecall to new implementation contract failed\\\");\\n return returndata;\\n }\\n\\n /**\\n * @notice Changes the owner of the proxy contract. Only callable by the owner.\\n *\\n * @param _admin New owner of the proxy contract.\\n */\\n function changeAdmin(address _admin) external proxyCallIfNotAdmin {\\n _changeAdmin(_admin);\\n }\\n\\n /**\\n * @notice Gets the owner of the proxy contract.\\n *\\n * @return Owner address.\\n */\\n function admin() external proxyCallIfNotAdmin returns (address) {\\n return _getAdmin();\\n }\\n\\n /**\\n * @notice Queries the implementation address.\\n *\\n * @return Implementation address.\\n */\\n function implementation() external proxyCallIfNotAdmin returns (address) {\\n return _getImplementation();\\n }\\n\\n /**\\n * @notice Sets the implementation address.\\n *\\n * @param _implementation New implementation address.\\n */\\n function _setImplementation(address _implementation) internal {\\n assembly {\\n sstore(IMPLEMENTATION_KEY, _implementation)\\n }\\n emit Upgraded(_implementation);\\n }\\n\\n /**\\n * @notice Changes the owner of the proxy contract.\\n *\\n * @param _admin New owner of the proxy contract.\\n */\\n function _changeAdmin(address _admin) internal {\\n address previous = _getAdmin();\\n assembly {\\n sstore(OWNER_KEY, _admin)\\n }\\n emit AdminChanged(previous, _admin);\\n }\\n\\n /**\\n * @notice Performs the proxy call via a delegatecall.\\n */\\n function _doProxyCall() internal {\\n address impl = _getImplementation();\\n require(impl != address(0), \\\"Proxy: implementation not initialized\\\");\\n\\n assembly {\\n // Copy calldata into memory at 0x0....calldatasize.\\n calldatacopy(0x0, 0x0, calldatasize())\\n\\n // Perform the delegatecall, make sure to pass all available gas.\\n let success := delegatecall(gas(), impl, 0x0, calldatasize(), 0x0, 0x0)\\n\\n // Copy returndata into memory at 0x0....returndatasize. Note that this *will*\\n // overwrite the calldata that we just copied into memory but that doesn't really\\n // matter because we'll be returning in a second anyway.\\n returndatacopy(0x0, 0x0, returndatasize())\\n\\n // Success == 0 means a revert. We'll revert too and pass the data up.\\n if iszero(success) {\\n revert(0x0, returndatasize())\\n }\\n\\n // Otherwise we'll just return and pass the data up.\\n return(0x0, returndatasize())\\n }\\n }\\n\\n /**\\n * @notice Queries the implementation address.\\n *\\n * @return Implementation address.\\n */\\n function _getImplementation() internal view returns (address) {\\n address impl;\\n assembly {\\n impl := sload(IMPLEMENTATION_KEY)\\n }\\n return impl;\\n }\\n\\n /**\\n * @notice Queries the owner of the proxy contract.\\n *\\n * @return Owner address.\\n */\\n function _getAdmin() internal view returns (address) {\\n address owner;\\n assembly {\\n owner := sload(OWNER_KEY)\\n }\\n return owner;\\n }\\n}\\n\",\"keccak256\":\"0xfa08635f1866139673ac4fe7b07330f752f93800075b895d8fcb8484f4a3f753\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b5060405161094138038061094183398101604081905261002f916100b2565b6100388161003e565b506100e2565b60006100566000805160206109218339815191525490565b600080516020610921833981519152839055604080516001600160a01b038084168252851660208201529192507f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f910160405180910390a15050565b6000602082840312156100c457600080fd5b81516001600160a01b03811681146100db57600080fd5b9392505050565b610830806100f16000396000f3fe60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100be5780638f283970146100f8578063f851a440146101185761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61012d565b005b61006b61012d565b34801561008157600080fd5b5061006b6100903660046106d9565b610224565b6100a86100a33660046106f4565b610296565b6040516100b59190610777565b60405180910390f35b3480156100ca57600080fd5b506100d3610419565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b5565b34801561010457600080fd5b5061006b6101133660046106d9565b6104b0565b34801561012457600080fd5b506100d3610517565b60006101577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b905073ffffffffffffffffffffffffffffffffffffffff8116610201576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f50726f78793a20696d706c656d656e746174696f6e206e6f7420696e6974696160448201527f6c697a656400000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b3660008037600080366000845af43d6000803e8061021e573d6000fd5b503d6000f35b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061027d575033155b1561028e5761028b816105a3565b50565b61028b61012d565b60606102c07fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102f7575033155b1561040a57610305846105a3565b6000808573ffffffffffffffffffffffffffffffffffffffff16858560405161032f9291906107ea565b600060405180830381855af49150503d806000811461036a576040519150601f19603f3d011682016040523d82523d6000602084013e61036f565b606091505b509150915081610401576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f50726f78793a2064656c656761746563616c6c20746f206e657720696d706c6560448201527f6d656e746174696f6e20636f6e7472616374206661696c65640000000000000060648201526084016101f8565b91506104129050565b61041261012d565b9392505050565b60006104437fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061047a575033155b156104a557507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6104ad61012d565b90565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610509575033155b1561028e5761028b8161060b565b60006105417fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610578575033155b156104a557507fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81905560405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60006106357fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61038390556040805173ffffffffffffffffffffffffffffffffffffffff8084168252851660208201529192507f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f910160405180910390a15050565b803573ffffffffffffffffffffffffffffffffffffffff811681146106d457600080fd5b919050565b6000602082840312156106eb57600080fd5b610412826106b0565b60008060006040848603121561070957600080fd5b610712846106b0565b9250602084013567ffffffffffffffff8082111561072f57600080fd5b818601915086601f83011261074357600080fd5b81358181111561075257600080fd5b87602082850101111561076457600080fd5b6020830194508093505050509250925092565b600060208083528351808285015260005b818110156107a457858101830151858201604001528201610788565b818111156107b6576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b818382376000910190815291905056fea2646970667358221220120210f19dd8be0e46312b3b9a2148bbb98ec24cce2aa05af1c3d1fe69f55b2b64736f6c634300080f0033b53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103",
"deployedBytecode": "0x60806040526004361061005e5760003560e01c80635c60da1b116100435780635c60da1b146100be5780638f283970146100f8578063f851a440146101185761006d565b80633659cfe6146100755780634f1ef286146100955761006d565b3661006d5761006b61012d565b005b61006b61012d565b34801561008157600080fd5b5061006b6100903660046106d9565b610224565b6100a86100a33660046106f4565b610296565b6040516100b59190610777565b60405180910390f35b3480156100ca57600080fd5b506100d3610419565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020016100b5565b34801561010457600080fd5b5061006b6101133660046106d9565b6104b0565b34801561012457600080fd5b506100d3610517565b60006101577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b905073ffffffffffffffffffffffffffffffffffffffff8116610201576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602560248201527f50726f78793a20696d706c656d656e746174696f6e206e6f7420696e6974696160448201527f6c697a656400000000000000000000000000000000000000000000000000000060648201526084015b60405180910390fd5b3660008037600080366000845af43d6000803e8061021e573d6000fd5b503d6000f35b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061027d575033155b1561028e5761028b816105a3565b50565b61028b61012d565b60606102c07fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614806102f7575033155b1561040a57610305846105a3565b6000808573ffffffffffffffffffffffffffffffffffffffff16858560405161032f9291906107ea565b600060405180830381855af49150503d806000811461036a576040519150601f19603f3d011682016040523d82523d6000602084013e61036f565b606091505b509150915081610401576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603960248201527f50726f78793a2064656c656761746563616c6c20746f206e657720696d706c6560448201527f6d656e746174696f6e20636f6e7472616374206661696c65640000000000000060648201526084016101f8565b91506104129050565b61041261012d565b9392505050565b60006104437fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff16148061047a575033155b156104a557507f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc5490565b6104ad61012d565b90565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035473ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610509575033155b1561028e5761028b8161060b565b60006105417fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161480610578575033155b156104a557507fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc81905560405173ffffffffffffffffffffffffffffffffffffffff8216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b60006106357fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61035490565b7fb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d61038390556040805173ffffffffffffffffffffffffffffffffffffffff8084168252851660208201529192507f7e644d79422f17c01e4894b5f4f588d331ebfa28653d42ae832dc59e38c9798f910160405180910390a15050565b803573ffffffffffffffffffffffffffffffffffffffff811681146106d457600080fd5b919050565b6000602082840312156106eb57600080fd5b610412826106b0565b60008060006040848603121561070957600080fd5b610712846106b0565b9250602084013567ffffffffffffffff8082111561072f57600080fd5b818601915086601f83011261074357600080fd5b81358181111561075257600080fd5b87602082850101111561076457600080fd5b6020830194508093505050509250925092565b600060208083528351808285015260005b818110156107a457858101830151858201604001528201610788565b818111156107b6576000604083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016929092016040019392505050565b818382376000910190815291905056fea2646970667358221220120210f19dd8be0e46312b3b9a2148bbb98ec24cce2aa05af1c3d1fe69f55b2b64736f6c634300080f0033",
"devdoc": {
"events": {
"AdminChanged(address,address)": {
"params": {
"newAdmin": "The new owner of the contract",
"previousAdmin": "The previous owner of the contract"
}
},
"Upgraded(address)": {
"params": {
"implementation": "The address of the implementation contract"
}
}
},
"kind": "dev",
"methods": {
"admin()": {
"returns": {
"_0": "Owner address."
}
},
"changeAdmin(address)": {
"params": {
"_admin": "New owner of the proxy contract."
}
},
"constructor": {
"params": {
"_admin": "Address of the initial contract admin. Admin as the ability to access the transparent proxy interface."
}
},
"implementation()": {
"returns": {
"_0": "Implementation address."
}
},
"upgradeTo(address)": {
"params": {
"_implementation": "Address of the implementation contract."
}
},
"upgradeToAndCall(address,bytes)": {
"params": {
"_data": "Calldata to delegatecall the new implementation with.",
"_implementation": "Address of the implementation contract."
}
}
},
"title": "Proxy",
"version": 1
},
"userdoc": {
"events": {
"AdminChanged(address,address)": {
"notice": "An event that is emitted each time the owner is upgraded. This event is part of the EIP-1967 specification."
},
"Upgraded(address)": {
"notice": "An event that is emitted each time the implementation is changed. This event is part of the EIP-1967 specification."
}
},
"kind": "user",
"methods": {
"admin()": {
"notice": "Gets the owner of the proxy contract."
},
"changeAdmin(address)": {
"notice": "Changes the owner of the proxy contract. Only callable by the owner."
},
"constructor": {
"notice": "Sets the initial admin during contract deployment. Admin address is stored at the EIP-1967 admin storage slot so that accidental storage collision with the implementation is not possible."
},
"implementation()": {
"notice": "Queries the implementation address."
},
"upgradeTo(address)": {
"notice": "Set the implementation contract address. The code at the given address will execute when this contract is called."
},
"upgradeToAndCall(address,bytes)": {
"notice": "Set the implementation and call a function in a single transaction. Useful to ensure atomic execution of initialization-based upgrades."
}
},
"notice": "Proxy is a transparent proxy that passes through the call if the caller is the owner or if the caller is address(0), meaning that the call originated from an off-chain simulation.",
"version": 1
},
"storageLayout": {
"storage": [],
"types": null
}
}
\ No newline at end of file
{
"language": "Solidity",
"sources": {
"contracts/universal/AssetReceiver.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\nimport { Transactor } from \"./Transactor.sol\";\n\n/**\n * @title AssetReceiver\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\n */\ncontract AssetReceiver is Transactor {\n /**\n * Emitted when ETH is received by this address.\n */\n event ReceivedETH(address indexed from, uint256 amount);\n\n /**\n * Emitted when ETH is withdrawn from this address.\n */\n event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\n\n /**\n * Emitted when ERC20 tokens are withdrawn from this address.\n */\n event WithdrewERC20(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 amount\n );\n\n /**\n * Emitted when ERC721 tokens are withdrawn from this address.\n */\n event WithdrewERC721(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 id\n );\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Transactor(_owner) {}\n\n /**\n * Make sure we can receive ETH.\n */\n receive() external payable {\n emit ReceivedETH(msg.sender, msg.value);\n }\n\n /**\n * Withdraws full ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n */\n function withdrawETH(address payable _to) external onlyOwner {\n withdrawETH(_to, address(this).balance);\n }\n\n /**\n * Withdraws partial ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n * @param _amount Amount of ETH to withdraw.\n */\n function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\n // slither-disable-next-line reentrancy-unlimited-gas\n _to.transfer(_amount);\n emit WithdrewETH(msg.sender, _to, _amount);\n }\n\n /**\n * Withdraws full ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n */\n function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\n withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\n }\n\n /**\n * Withdraws partial ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n * @param _amount Amount of ERC20 to withdraw.\n */\n function withdrawERC20(\n ERC20 _asset,\n address _to,\n uint256 _amount\n ) public onlyOwner {\n // slither-disable-next-line unchecked-transfer\n _asset.transfer(_to, _amount);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\n }\n\n /**\n * Withdraws ERC721 token to the recipient.\n *\n * @param _asset ERC721 token to withdraw.\n * @param _to Address to receive the ERC721 token.\n * @param _id Token ID of the ERC721 token to withdraw.\n */\n function withdrawERC721(\n ERC721 _asset,\n address _to,\n uint256 _id\n ) external onlyOwner {\n _asset.transferFrom(address(this), _to, _id);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n uint8 public immutable decimals;\n\n /*//////////////////////////////////////////////////////////////\n ERC20 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 public totalSupply;\n\n mapping(address => uint256) public balanceOf;\n\n mapping(address => mapping(address => uint256)) public allowance;\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal immutable INITIAL_CHAIN_ID;\n\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n mapping(address => uint256) public nonces;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals\n ) {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n INITIAL_CHAIN_ID = block.chainid;\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 amount) public virtual returns (bool) {\n allowance[msg.sender][spender] = amount;\n\n emit Approval(msg.sender, spender, amount);\n\n return true;\n }\n\n function transfer(address to, uint256 amount) public virtual returns (bool) {\n balanceOf[msg.sender] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(msg.sender, to, amount);\n\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual returns (bool) {\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n balanceOf[from] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual {\n require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n // Unchecked because the only math done is incrementing\n // the owner's nonce which cannot realistically overflow.\n unchecked {\n address recoveredAddress = ecrecover(\n keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(\n abi.encode(\n keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n ),\n owner,\n spender,\n value,\n nonces[owner]++,\n deadline\n )\n )\n )\n ),\n v,\n r,\n s\n );\n\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n allowance[recoveredAddress][spender] = value;\n }\n\n emit Approval(owner, spender, value);\n }\n\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n }\n\n function computeDomainSeparator() internal view virtual returns (bytes32) {\n return\n keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(name)),\n keccak256(\"1\"),\n block.chainid,\n address(this)\n )\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 amount) internal virtual {\n totalSupply += amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal virtual {\n balanceOf[from] -= amount;\n\n // Cannot underflow because a user's balance\n // will never be larger than the total supply.\n unchecked {\n totalSupply -= amount;\n }\n\n emit Transfer(from, address(0), amount);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) internal _ownerOf;\n\n mapping(address => uint256) internal _balanceOf;\n\n function ownerOf(uint256 id) public view virtual returns (address owner) {\n require((owner = _ownerOf[id]) != address(0), \"NOT_MINTED\");\n }\n\n function balanceOf(address owner) public view virtual returns (uint256) {\n require(owner != address(0), \"ZERO_ADDRESS\");\n\n return _balanceOf[owner];\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) public getApproved;\n\n mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 id) public virtual {\n address owner = _ownerOf[id];\n\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n getApproved[id] = spender;\n\n emit Approval(owner, spender, id);\n }\n\n function setApprovalForAll(address operator, bool approved) public virtual {\n isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n require(from == _ownerOf[id], \"WRONG_FROM\");\n\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(\n msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\n \"NOT_AUTHORIZED\"\n );\n\n // Underflow of the sender's balance is impossible because we check for\n // ownership above and the recipient's balance can't realistically overflow.\n unchecked {\n _balanceOf[from]--;\n\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n delete getApproved[id];\n\n emit Transfer(from, to, id);\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n bytes calldata data\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 id) internal virtual {\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(_ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n // Counter overflow is incredibly unrealistic.\n unchecked {\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n emit Transfer(address(0), to, id);\n }\n\n function _burn(uint256 id) internal virtual {\n address owner = _ownerOf[id];\n\n require(owner != address(0), \"NOT_MINTED\");\n\n // Ownership check above ensures no underflow.\n unchecked {\n _balanceOf[owner]--;\n }\n\n delete _ownerOf[id];\n\n delete getApproved[id];\n\n emit Transfer(owner, address(0), id);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL SAFE MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _safeMint(address to, uint256 id) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _safeMint(\n address to,\n uint256 id,\n bytes memory data\n ) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721TokenReceiver {\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external virtual returns (bytes4) {\n return ERC721TokenReceiver.onERC721Received.selector;\n }\n}\n"
},
"contracts/universal/Transactor.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { Owned } from \"@rari-capital/solmate/src/auth/Owned.sol\";\n\n/**\n * @title Transactor\n * @notice Transactor is a minimal contract that can send transactions.\n */\ncontract Transactor is Owned {\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Owned(_owner) {}\n\n /**\n * Sends a CALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @param _value ETH value to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function CALL(\n address _target,\n bytes memory _data,\n uint256 _gas,\n uint256 _value\n ) external payable onlyOwner returns (bool, bytes memory) {\n return _target.call{ gas: _gas, value: _value }(_data);\n }\n\n /**\n * Sends a DELEGATECALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function DELEGATECALL(\n address _target,\n bytes memory _data,\n uint256 _gas\n ) external payable onlyOwner returns (bool, bytes memory) {\n // slither-disable-next-line controlled-delegatecall\n return _target.delegatecall{ gas: _gas }(_data);\n }\n}\n"
},
"@rari-capital/solmate/src/auth/Owned.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event OwnerUpdated(address indexed user, address indexed newOwner);\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP STORAGE\n //////////////////////////////////////////////////////////////*/\n\n address public owner;\n\n modifier onlyOwner() virtual {\n require(msg.sender == owner, \"UNAUTHORIZED\");\n\n _;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address _owner) {\n owner = _owner;\n\n emit OwnerUpdated(address(0), _owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function setOwner(address newOwner) public virtual onlyOwner {\n owner = newOwner;\n\n emit OwnerUpdated(msg.sender, newOwner);\n }\n}\n"
},
"contracts/universal/drippie/Drippie.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { AssetReceiver } from \"../AssetReceiver.sol\";\nimport { IDripCheck } from \"./IDripCheck.sol\";\n\n/**\n * @title Drippie\n * @notice Drippie is a system for managing automated contract interactions. A specific interaction\n * is called a \"drip\" and can be executed according to some condition (called a dripcheck) and an\n * execution interval. Drips cannot be executed faster than the execution interval. Drips can\n * trigger arbitrary contract calls where the calling contract is this contract address. Drips can\n * also send ETH value, which makes them ideal for keeping addresses sufficiently funded with ETH.\n * Drippie is designed to be connected with smart contract automation services so that drips can be\n * executed automatically. However, Drippie is specifically designed to be separated from these\n * services so that trust assumptions are better compartmentalized.\n */\ncontract Drippie is AssetReceiver {\n /**\n * Enum representing different status options for a given drip.\n */\n enum DripStatus {\n NONE,\n ACTIVE,\n PAUSED,\n ARCHIVED\n }\n\n /**\n * Represents a drip action.\n */\n struct DripAction {\n address payable target;\n bytes data;\n uint256 value;\n }\n\n /**\n * Represents the configuration for a given drip.\n */\n struct DripConfig {\n uint256 interval;\n IDripCheck dripcheck;\n bytes checkparams;\n DripAction[] actions;\n }\n\n /**\n * Represents the state of an active drip.\n */\n struct DripState {\n DripStatus status;\n DripConfig config;\n uint256 last;\n }\n\n /**\n * Emitted when a new drip is created.\n */\n event DripCreated(string indexed name, DripConfig config);\n\n /**\n * Emitted when a drip status is updated.\n */\n event DripStatusUpdated(string indexed name, DripStatus status);\n\n /**\n * Emitted when a drip is executed.\n */\n event DripExecuted(string indexed name, address indexed executor, uint256 timestamp);\n\n /**\n * Maps from drip names to drip states.\n */\n mapping(string => DripState) public drips;\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) AssetReceiver(_owner) {}\n\n /**\n * Creates a new drip with the given name and configuration. Once created, drips cannot be\n * modified in any way (this is a security measure). If you want to update a drip, simply pause\n * (and potentially archive) the existing drip and create a new one.\n *\n * @param _name Name of the drip.\n * @param _config Configuration for the drip.\n */\n function create(string memory _name, DripConfig memory _config) external onlyOwner {\n // Make sure this drip doesn't already exist. We *must* guarantee that no other function\n // will ever set the status of a drip back to NONE after it's been created. This is why\n // archival is a separate status.\n require(\n drips[_name].status == DripStatus.NONE,\n \"Drippie: drip with that name already exists\"\n );\n\n // We initialize this way because Solidity won't let us copy arrays into storage yet.\n DripState storage state = drips[_name];\n state.status = DripStatus.PAUSED;\n state.config.interval = _config.interval;\n state.config.dripcheck = _config.dripcheck;\n state.config.checkparams = _config.checkparams;\n\n // Solidity doesn't let us copy arrays into storage, so we push each array one by one.\n for (uint256 i = 0; i < _config.actions.length; i++) {\n state.config.actions.push(_config.actions[i]);\n }\n\n // Tell the world!\n emit DripCreated(_name, _config);\n }\n\n /**\n * Sets the status for a given drip. The behavior of this function depends on the status that\n * the user is trying to set. A drip can always move between ACTIVE and PAUSED, but it can\n * never move back to NONE and once ARCHIVED, it can never move back to ACTIVE or PAUSED.\n *\n * @param _name Name of the drip to update.\n * @param _status New drip status.\n */\n function status(string memory _name, DripStatus _status) external onlyOwner {\n // Make sure we can never set drip status back to NONE. A simple security measure to\n // prevent accidental overwrites if this code is ever updated down the line.\n require(\n _status != DripStatus.NONE,\n \"Drippie: drip status can never be set back to NONE after creation\"\n );\n\n // Make sure the drip in question actually exists. Not strictly necessary but there doesn't\n // seem to be any clear reason why you would want to do this, and it may save some gas in\n // the case of a front-end bug.\n require(\n drips[_name].status != DripStatus.NONE,\n \"Drippie: drip with that name does not exist\"\n );\n\n // Once a drip has been archived, it cannot be un-archived. This is, after all, the entire\n // point of archiving a drip.\n require(\n drips[_name].status != DripStatus.ARCHIVED,\n \"Drippie: drip with that name has been archived\"\n );\n\n // Although not strictly necessary, we make sure that the status here is actually changing.\n // This may save the client some gas if there's a front-end bug and the user accidentally\n // tries to \"change\" the status to the same value as before.\n require(\n drips[_name].status != _status,\n \"Drippie: cannot set drip status to same status as before\"\n );\n\n // If the user is trying to archive this drip, make sure the drip has been paused. We do\n // not allow users to archive active drips so that the effects of this action are more\n // abundantly clear.\n if (_status == DripStatus.ARCHIVED) {\n require(\n drips[_name].status == DripStatus.PAUSED,\n \"Drippie: drip must be paused to be archived\"\n );\n }\n\n // If we made it here then we can safely update the status.\n drips[_name].status = _status;\n emit DripStatusUpdated(_name, drips[_name].status);\n }\n\n /**\n * Triggers a drip. This function is deliberately left as a public function because the\n * assumption being made here is that setting the drip to ACTIVE is an affirmative signal that\n * the drip should be executable according to the drip parameters, drip check, and drip\n * interval. Note that drip parameters are read entirely from the state and are not supplied as\n * user input, so there should not be any way for a non-authorized user to influence the\n * behavior of the drip.\n *\n * @param _name Name of the drip to trigger.\n */\n function drip(string memory _name) external {\n DripState storage state = drips[_name];\n\n // Only allow active drips to be executed, an obvious security measure.\n require(\n state.status == DripStatus.ACTIVE,\n \"Drippie: selected drip does not exist or is not currently active\"\n );\n\n // Don't drip if the drip interval has not yet elapsed since the last time we dripped. This\n // is a safety measure that prevents a malicious recipient from, e.g., spending all of\n // their funds and repeatedly requesting new drips. Limits the potential impact of a\n // compromised recipient to just a single drip interval, after which the drip can be paused\n // by the owner address.\n require(\n state.last + state.config.interval <= block.timestamp,\n \"Drippie: drip interval has not elapsed since last drip\"\n );\n\n // Make sure we're allowed to execute this drip.\n require(\n state.config.dripcheck.check(state.config.checkparams),\n \"Drippie: dripcheck failed so drip is not yet ready to be triggered\"\n );\n\n // Update the last execution time for this drip before the call. Note that it's entirely\n // possible for a drip to be executed multiple times per block or even multiple times\n // within the same transaction (via re-entrancy) if the drip interval is set to zero. Users\n // should set a drip interval of 1 if they'd like the drip to be executed only once per\n // block (since this will then prevent re-entrancy).\n state.last = block.timestamp;\n\n // Execute each action in the drip. We allow drips to have multiple actions because there\n // are scenarios in which a contract must do multiple things atomically. For example, the\n // contract may need to withdraw ETH from one account and then deposit that ETH into\n // another account within the same transaction.\n uint256 len = state.config.actions.length;\n for (uint256 i = 0; i < len; i++) {\n // Must be marked as \"storage\" because copying structs into memory is not yet supported\n // by Solidity. Won't significantly reduce gas costs but at least makes it easier to\n // read what the rest of this section is doing.\n DripAction storage action = state.config.actions[i];\n\n // Actually execute the action. We could use ExcessivelySafeCall here but not strictly\n // necessary (worst case, a drip gets bricked IFF the target is malicious, doubt this\n // will ever happen in practice). Could save a marginal amount of gas to ignore the\n // returndata.\n // slither-disable-next-line calls-loop\n (bool success, ) = action.target.call{ value: action.value }(action.data);\n\n // Generally should not happen, but could if there's a misconfiguration (e.g., passing\n // the wrong data to the target contract), the recipient is not payable, or\n // insufficient gas was supplied to this transaction. We revert so the drip can be\n // fixed and triggered again later. Means we cannot emit an event to alert of the\n // failure, but can reasonably be detected by off-chain services even without an event.\n // Note that this forces the drip executor to supply sufficient gas to the call\n // (assuming there is some sufficient gas limit that exists, otherwise the drip will\n // not execute).\n require(\n success,\n \"Drippie: drip was unsuccessful, please check your configuration for mistakes\"\n );\n }\n\n emit DripExecuted(_name, msg.sender, block.timestamp);\n }\n}\n"
},
"contracts/universal/drippie/IDripCheck.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ninterface IDripCheck {\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\n // possible to easily encode parameters on the client side. Solidity does not support generics\n // so it's not possible to do this with explicit typing.\n\n function check(bytes memory _params) external view returns (bool);\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckTrue.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckTrue\n * @notice DripCheck that always returns true.\n */\ncontract CheckTrue is IDripCheck {\n function check(bytes memory) external pure returns (bool) {\n return true;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\ninterface IGelatoTreasury {\n function userTokenBalance(address _user, address _token) external view returns (uint256);\n}\n\n/**\n * @title CheckGelatoLow\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\n */\ncontract CheckGelatoLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address treasury;\n uint256 threshold;\n address recipient;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check GelatoTreasury ETH balance is below threshold.\n return\n IGelatoTreasury(params.treasury).userTokenBalance(\n params.recipient,\n // Gelato represents ETH as 0xeeeee....eeeee\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\n ) < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceLow\n * @notice DripCheck for checking if an account's balance is below a given threshold.\n */\ncontract CheckBalanceLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target ETH balance is below threshold.\n return params.target.balance < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceHigh\n * @notice DripCheck for checking if an account's balance is above a given threshold.\n */\ncontract CheckBalanceHigh is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target balance is above threshold.\n return params.target.balance > params.threshold;\n }\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
\ No newline at end of file
{
"language": "Solidity",
"sources": {
"contracts/universal/AssetReceiver.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\nimport { Transactor } from \"./Transactor.sol\";\n\n/**\n * @title AssetReceiver\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\n */\ncontract AssetReceiver is Transactor {\n /**\n * Emitted when ETH is received by this address.\n */\n event ReceivedETH(address indexed from, uint256 amount);\n\n /**\n * Emitted when ETH is withdrawn from this address.\n */\n event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\n\n /**\n * Emitted when ERC20 tokens are withdrawn from this address.\n */\n event WithdrewERC20(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 amount\n );\n\n /**\n * Emitted when ERC721 tokens are withdrawn from this address.\n */\n event WithdrewERC721(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 id\n );\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Transactor(_owner) {}\n\n /**\n * Make sure we can receive ETH.\n */\n receive() external payable {\n emit ReceivedETH(msg.sender, msg.value);\n }\n\n /**\n * Withdraws full ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n */\n function withdrawETH(address payable _to) external onlyOwner {\n withdrawETH(_to, address(this).balance);\n }\n\n /**\n * Withdraws partial ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n * @param _amount Amount of ETH to withdraw.\n */\n function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\n // slither-disable-next-line reentrancy-unlimited-gas\n _to.transfer(_amount);\n emit WithdrewETH(msg.sender, _to, _amount);\n }\n\n /**\n * Withdraws full ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n */\n function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\n withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\n }\n\n /**\n * Withdraws partial ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n * @param _amount Amount of ERC20 to withdraw.\n */\n function withdrawERC20(\n ERC20 _asset,\n address _to,\n uint256 _amount\n ) public onlyOwner {\n // slither-disable-next-line unchecked-transfer\n _asset.transfer(_to, _amount);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\n }\n\n /**\n * Withdraws ERC721 token to the recipient.\n *\n * @param _asset ERC721 token to withdraw.\n * @param _to Address to receive the ERC721 token.\n * @param _id Token ID of the ERC721 token to withdraw.\n */\n function withdrawERC721(\n ERC721 _asset,\n address _to,\n uint256 _id\n ) external onlyOwner {\n _asset.transferFrom(address(this), _to, _id);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC20.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n uint8 public immutable decimals;\n\n /*//////////////////////////////////////////////////////////////\n ERC20 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 public totalSupply;\n\n mapping(address => uint256) public balanceOf;\n\n mapping(address => mapping(address => uint256)) public allowance;\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal immutable INITIAL_CHAIN_ID;\n\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n mapping(address => uint256) public nonces;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals\n ) {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n INITIAL_CHAIN_ID = block.chainid;\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 amount) public virtual returns (bool) {\n allowance[msg.sender][spender] = amount;\n\n emit Approval(msg.sender, spender, amount);\n\n return true;\n }\n\n function transfer(address to, uint256 amount) public virtual returns (bool) {\n balanceOf[msg.sender] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(msg.sender, to, amount);\n\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual returns (bool) {\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n balanceOf[from] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual {\n require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n // Unchecked because the only math done is incrementing\n // the owner's nonce which cannot realistically overflow.\n unchecked {\n address recoveredAddress = ecrecover(\n keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(\n abi.encode(\n keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n ),\n owner,\n spender,\n value,\n nonces[owner]++,\n deadline\n )\n )\n )\n ),\n v,\n r,\n s\n );\n\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n allowance[recoveredAddress][spender] = value;\n }\n\n emit Approval(owner, spender, value);\n }\n\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n }\n\n function computeDomainSeparator() internal view virtual returns (bytes32) {\n return\n keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(name)),\n keccak256(\"1\"),\n block.chainid,\n address(this)\n )\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 amount) internal virtual {\n totalSupply += amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal virtual {\n balanceOf[from] -= amount;\n\n // Cannot underflow because a user's balance\n // will never be larger than the total supply.\n unchecked {\n totalSupply -= amount;\n }\n\n emit Transfer(from, address(0), amount);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC721.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) internal _ownerOf;\n\n mapping(address => uint256) internal _balanceOf;\n\n function ownerOf(uint256 id) public view virtual returns (address owner) {\n require((owner = _ownerOf[id]) != address(0), \"NOT_MINTED\");\n }\n\n function balanceOf(address owner) public view virtual returns (uint256) {\n require(owner != address(0), \"ZERO_ADDRESS\");\n\n return _balanceOf[owner];\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) public getApproved;\n\n mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 id) public virtual {\n address owner = _ownerOf[id];\n\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n getApproved[id] = spender;\n\n emit Approval(owner, spender, id);\n }\n\n function setApprovalForAll(address operator, bool approved) public virtual {\n isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n require(from == _ownerOf[id], \"WRONG_FROM\");\n\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(\n msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\n \"NOT_AUTHORIZED\"\n );\n\n // Underflow of the sender's balance is impossible because we check for\n // ownership above and the recipient's balance can't realistically overflow.\n unchecked {\n _balanceOf[from]--;\n\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n delete getApproved[id];\n\n emit Transfer(from, to, id);\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n transferFrom(from, to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n bytes calldata data\n ) public virtual {\n transferFrom(from, to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 id) internal virtual {\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(_ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n // Counter overflow is incredibly unrealistic.\n unchecked {\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n emit Transfer(address(0), to, id);\n }\n\n function _burn(uint256 id) internal virtual {\n address owner = _ownerOf[id];\n\n require(owner != address(0), \"NOT_MINTED\");\n\n // Ownership check above ensures no underflow.\n unchecked {\n _balanceOf[owner]--;\n }\n\n delete _ownerOf[id];\n\n delete getApproved[id];\n\n emit Transfer(owner, address(0), id);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL SAFE MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _safeMint(address to, uint256 id) internal virtual {\n _mint(to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _safeMint(\n address to,\n uint256 id,\n bytes memory data\n ) internal virtual {\n _mint(to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721TokenReceiver {\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external virtual returns (bytes4) {\n return ERC721TokenReceiver.onERC721Received.selector;\n }\n}\n"
},
"contracts/universal/Transactor.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { Owned } from \"@rari-capital/solmate/src/auth/Owned.sol\";\n\n/**\n * @title Transactor\n * @notice Transactor is a minimal contract that can send transactions.\n */\ncontract Transactor is Owned {\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Owned(_owner) {}\n\n /**\n * Sends a CALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @param _value ETH value to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function CALL(\n address _target,\n bytes memory _data,\n uint256 _gas,\n uint256 _value\n ) external payable onlyOwner returns (bool, bytes memory) {\n return _target.call{ gas: _gas, value: _value }(_data);\n }\n\n /**\n * Sends a DELEGATECALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function DELEGATECALL(\n address _target,\n bytes memory _data,\n uint256 _gas\n ) external payable onlyOwner returns (bool, bytes memory) {\n // slither-disable-next-line controlled-delegatecall\n return _target.delegatecall{ gas: _gas }(_data);\n }\n}\n"
},
"@rari-capital/solmate/src/auth/Owned.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event OwnerUpdated(address indexed user, address indexed newOwner);\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP STORAGE\n //////////////////////////////////////////////////////////////*/\n\n address public owner;\n\n modifier onlyOwner() virtual {\n require(msg.sender == owner, \"UNAUTHORIZED\");\n\n _;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address _owner) {\n owner = _owner;\n\n emit OwnerUpdated(address(0), _owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function setOwner(address newOwner) public virtual onlyOwner {\n owner = newOwner;\n\n emit OwnerUpdated(msg.sender, newOwner);\n }\n}\n"
},
"contracts/universal/drippie/Drippie.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { AssetReceiver } from \"../AssetReceiver.sol\";\nimport { IDripCheck } from \"./IDripCheck.sol\";\n\n/**\n * @title Drippie\n * @notice Drippie is a system for managing automated contract interactions. A specific interaction\n * is called a \"drip\" and can be executed according to some condition (called a dripcheck) and an\n * execution interval. Drips cannot be executed faster than the execution interval. Drips can\n * trigger arbitrary contract calls where the calling contract is this contract address. Drips can\n * also send ETH value, which makes them ideal for keeping addresses sufficiently funded with ETH.\n * Drippie is designed to be connected with smart contract automation services so that drips can be\n * executed automatically. However, Drippie is specifically designed to be separated from these\n * services so that trust assumptions are better compartmentalized.\n */\ncontract Drippie is AssetReceiver {\n /**\n * Enum representing different status options for a given drip.\n */\n enum DripStatus {\n NONE,\n ACTIVE,\n PAUSED,\n ARCHIVED\n }\n\n /**\n * Represents a drip action.\n */\n struct DripAction {\n address payable target;\n bytes data;\n uint256 value;\n }\n\n /**\n * Represents the configuration for a given drip.\n */\n struct DripConfig {\n uint256 interval;\n IDripCheck dripcheck;\n bytes checkparams;\n DripAction[] actions;\n }\n\n /**\n * Represents the state of an active drip.\n */\n struct DripState {\n DripStatus status;\n DripConfig config;\n uint256 last;\n }\n\n /**\n * Emitted when a new drip is created.\n */\n event DripCreated(string indexed name, DripConfig config);\n\n /**\n * Emitted when a drip status is updated.\n */\n event DripStatusUpdated(string indexed name, DripStatus status);\n\n /**\n * Emitted when a drip is executed.\n */\n event DripExecuted(string indexed name, address indexed executor, uint256 timestamp);\n\n /**\n * Maps from drip names to drip states.\n */\n mapping(string => DripState) public drips;\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) AssetReceiver(_owner) {}\n\n /**\n * Creates a new drip with the given name and configuration. Once created, drips cannot be\n * modified in any way (this is a security measure). If you want to update a drip, simply pause\n * (and potentially archive) the existing drip and create a new one.\n *\n * @param _name Name of the drip.\n * @param _config Configuration for the drip.\n */\n function create(string memory _name, DripConfig memory _config) external onlyOwner {\n // Make sure this drip doesn't already exist. We *must* guarantee that no other function\n // will ever set the status of a drip back to NONE after it's been created. This is why\n // archival is a separate status.\n require(\n drips[_name].status == DripStatus.NONE,\n \"Drippie: drip with that name already exists\"\n );\n\n // We initialize this way because Solidity won't let us copy arrays into storage yet.\n DripState storage state = drips[_name];\n state.status = DripStatus.PAUSED;\n state.config.interval = _config.interval;\n state.config.dripcheck = _config.dripcheck;\n state.config.checkparams = _config.checkparams;\n\n // Solidity doesn't let us copy arrays into storage, so we push each array one by one.\n for (uint256 i = 0; i < _config.actions.length; i++) {\n state.config.actions.push(_config.actions[i]);\n }\n\n // Tell the world!\n emit DripCreated(_name, _config);\n }\n\n /**\n * Sets the status for a given drip. The behavior of this function depends on the status that\n * the user is trying to set. A drip can always move between ACTIVE and PAUSED, but it can\n * never move back to NONE and once ARCHIVED, it can never move back to ACTIVE or PAUSED.\n *\n * @param _name Name of the drip to update.\n * @param _status New drip status.\n */\n function status(string memory _name, DripStatus _status) external onlyOwner {\n // Make sure we can never set drip status back to NONE. A simple security measure to\n // prevent accidental overwrites if this code is ever updated down the line.\n require(\n _status != DripStatus.NONE,\n \"Drippie: drip status can never be set back to NONE after creation\"\n );\n\n // Make sure the drip in question actually exists. Not strictly necessary but there doesn't\n // seem to be any clear reason why you would want to do this, and it may save some gas in\n // the case of a front-end bug.\n require(\n drips[_name].status != DripStatus.NONE,\n \"Drippie: drip with that name does not exist\"\n );\n\n // Once a drip has been archived, it cannot be un-archived. This is, after all, the entire\n // point of archiving a drip.\n require(\n drips[_name].status != DripStatus.ARCHIVED,\n \"Drippie: drip with that name has been archived\"\n );\n\n // Although not strictly necessary, we make sure that the status here is actually changing.\n // This may save the client some gas if there's a front-end bug and the user accidentally\n // tries to \"change\" the status to the same value as before.\n require(\n drips[_name].status != _status,\n \"Drippie: cannot set drip status to same status as before\"\n );\n\n // If the user is trying to archive this drip, make sure the drip has been paused. We do\n // not allow users to archive active drips so that the effects of this action are more\n // abundantly clear.\n if (_status == DripStatus.ARCHIVED) {\n require(\n drips[_name].status == DripStatus.PAUSED,\n \"Drippie: drip must be paused to be archived\"\n );\n }\n\n // If we made it here then we can safely update the status.\n drips[_name].status = _status;\n emit DripStatusUpdated(_name, drips[_name].status);\n }\n\n /**\n * Triggers a drip. This function is deliberately left as a public function because the\n * assumption being made here is that setting the drip to ACTIVE is an affirmative signal that\n * the drip should be executable according to the drip parameters, drip check, and drip\n * interval. Note that drip parameters are read entirely from the state and are not supplied as\n * user input, so there should not be any way for a non-authorized user to influence the\n * behavior of the drip.\n *\n * @param _name Name of the drip to trigger.\n */\n function drip(string memory _name) external {\n DripState storage state = drips[_name];\n\n // Only allow active drips to be executed, an obvious security measure.\n require(\n state.status == DripStatus.ACTIVE,\n \"Drippie: selected drip does not exist or is not currently active\"\n );\n\n // Don't drip if the drip interval has not yet elapsed since the last time we dripped. This\n // is a safety measure that prevents a malicious recipient from, e.g., spending all of\n // their funds and repeatedly requesting new drips. Limits the potential impact of a\n // compromised recipient to just a single drip interval, after which the drip can be paused\n // by the owner address.\n require(\n state.last + state.config.interval <= block.timestamp,\n \"Drippie: drip interval has not elapsed since last drip\"\n );\n\n // Make sure we're allowed to execute this drip.\n require(\n state.config.dripcheck.check(state.config.checkparams),\n \"Drippie: dripcheck failed so drip is not yet ready to be triggered\"\n );\n\n // Update the last execution time for this drip before the call. Note that it's entirely\n // possible for a drip to be executed multiple times per block or even multiple times\n // within the same transaction (via re-entrancy) if the drip interval is set to zero. Users\n // should set a drip interval of 1 if they'd like the drip to be executed only once per\n // block (since this will then prevent re-entrancy).\n state.last = block.timestamp;\n\n // Execute each action in the drip. We allow drips to have multiple actions because there\n // are scenarios in which a contract must do multiple things atomically. For example, the\n // contract may need to withdraw ETH from one account and then deposit that ETH into\n // another account within the same transaction.\n uint256 len = state.config.actions.length;\n for (uint256 i = 0; i < len; i++) {\n // Must be marked as \"storage\" because copying structs into memory is not yet supported\n // by Solidity. Won't significantly reduce gas costs but at least makes it easier to\n // read what the rest of this section is doing.\n DripAction storage action = state.config.actions[i];\n\n // Actually execute the action. We could use ExcessivelySafeCall here but not strictly\n // necessary (worst case, a drip gets bricked IFF the target is malicious, doubt this\n // will ever happen in practice). Could save a marginal amount of gas to ignore the\n // returndata.\n // slither-disable-next-line calls-loop\n (bool success, ) = action.target.call{ value: action.value }(action.data);\n\n // Generally should not happen, but could if there's a misconfiguration (e.g., passing\n // the wrong data to the target contract), the recipient is not payable, or\n // insufficient gas was supplied to this transaction. We revert so the drip can be\n // fixed and triggered again later. Means we cannot emit an event to alert of the\n // failure, but can reasonably be detected by off-chain services even without an event.\n // Note that this forces the drip executor to supply sufficient gas to the call\n // (assuming there is some sufficient gas limit that exists, otherwise the drip will\n // not execute).\n require(\n success,\n \"Drippie: drip was unsuccessful, please check your configuration for mistakes\"\n );\n }\n\n emit DripExecuted(_name, msg.sender, block.timestamp);\n }\n}\n"
},
"contracts/universal/drippie/IDripCheck.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ninterface IDripCheck {\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\n // possible to easily encode parameters on the client side. Solidity does not support generics\n // so it's not possible to do this with explicit typing.\n\n function check(bytes memory _params) external view returns (bool);\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckTrue.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckTrue\n * @notice DripCheck that always returns true.\n */\ncontract CheckTrue is IDripCheck {\n function check(bytes memory) external pure returns (bool) {\n return true;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\ninterface IGelatoTreasury {\n function userTokenBalance(address _user, address _token) external view returns (uint256);\n}\n\n/**\n * @title CheckGelatoLow\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\n */\ncontract CheckGelatoLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address treasury;\n uint256 threshold;\n address recipient;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check GelatoTreasury ETH balance is below threshold.\n return\n IGelatoTreasury(params.treasury).userTokenBalance(\n params.recipient,\n // Gelato represents ETH as 0xeeeee....eeeee\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\n ) < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceLow\n * @notice DripCheck for checking if an account's balance is below a given threshold.\n */\ncontract CheckBalanceLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target ETH balance is below threshold.\n return params.target.balance < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceHigh\n * @notice DripCheck for checking if an account's balance is above a given threshold.\n */\ncontract CheckBalanceHigh is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target balance is above threshold.\n return params.target.balance > params.threshold;\n }\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
\ No newline at end of file
{
"address": "0x15DdA60616Ffca20371ED1659dBB78E888f65556",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "_owner",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "user",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnerUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "ReceivedETH",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "withdrawer",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "asset",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "WithdrewERC20",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "withdrawer",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "asset",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "WithdrewERC721",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "withdrawer",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "WithdrewETH",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "_target",
"type": "address"
},
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "_gas",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "CALL",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_target",
"type": "address"
},
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "_gas",
"type": "uint256"
}
],
"name": "DELEGATECALL",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "setOwner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ERC20",
"name": "_asset",
"type": "address"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "withdrawERC20",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ERC20",
"name": "_asset",
"type": "address"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
}
],
"name": "withdrawERC20",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ERC721",
"name": "_asset",
"type": "address"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_id",
"type": "uint256"
}
],
"name": "withdrawERC721",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address payable",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "withdrawETH",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address payable",
"name": "_to",
"type": "address"
}
],
"name": "withdrawETH",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
],
"transactionHash": "0xb71ff0a1159385a03ad097a57d1cb37b62c5d6bc82be2e642a8d25d4ff4e1814",
"receipt": {
"to": "0x4e59b44847b379578588920cA78FbF26c0B4956C",
"from": "0x9C6373dE60c2D3297b18A8f964618ac46E011B58",
"contractAddress": null,
"transactionIndex": 31,
"gasUsed": "887432",
"logsBloom": "0x00100000000000000001000000000000000000000000000000000000000000000000100000000000000000100000080000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000800000000000000000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000020000000000000000000000000000000000000000000000",
"blockHash": "0x2b65d7c70a739ca85d8fd598096aa680cd2eb267e73036afd4cb974edebda524",
"transactionHash": "0xb71ff0a1159385a03ad097a57d1cb37b62c5d6bc82be2e642a8d25d4ff4e1814",
"logs": [
{
"transactionIndex": 31,
"blockNumber": 14904330,
"transactionHash": "0xb71ff0a1159385a03ad097a57d1cb37b62c5d6bc82be2e642a8d25d4ff4e1814",
"address": "0x15DdA60616Ffca20371ED1659dBB78E888f65556",
"topics": [
"0x8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000009c6373de60c2d3297b18a8f964618ac46e011b58"
],
"data": "0x",
"logIndex": 57,
"blockHash": "0x2b65d7c70a739ca85d8fd598096aa680cd2eb267e73036afd4cb974edebda524"
}
],
"blockNumber": 14904330,
"cumulativeGasUsed": "3130678",
"status": 1,
"byzantium": true
},
"args": [
"0x9C6373dE60c2D3297b18A8f964618ac46E011B58"
],
"numDeployments": 2,
"solcInputHash": "66d28de48de020e62747d42ffe3118e7",
"metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ReceivedETH\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrewERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"WithdrewERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrewETH\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"CALL\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gas\",\"type\":\"uint256\"}],\"name\":\"DELEGATECALL\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ERC721\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"}],\"name\":\"withdrawERC721\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdrawETH\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_to\",\"type\":\"address\"}],\"name\":\"withdrawETH\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"CALL(address,bytes,uint256,uint256)\":{\"params\":{\"_data\":\"Data to send with the call.\",\"_gas\":\"Amount of gas to send with the call.\",\"_target\":\"Address to call.\",\"_value\":\"ETH value to send with the call.\"},\"returns\":{\"_0\":\"Boolean success value.\",\"_1\":\"Bytes data returned by the call.\"}},\"DELEGATECALL(address,bytes,uint256)\":{\"params\":{\"_data\":\"Data to send with the call.\",\"_gas\":\"Amount of gas to send with the call.\",\"_target\":\"Address to call.\"},\"returns\":{\"_0\":\"Boolean success value.\",\"_1\":\"Bytes data returned by the call.\"}},\"constructor\":{\"params\":{\"_owner\":\"Initial contract owner.\"}},\"withdrawERC20(address,address)\":{\"params\":{\"_asset\":\"ERC20 token to withdraw.\",\"_to\":\"Address to receive the ERC20 balance.\"}},\"withdrawERC20(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of ERC20 to withdraw.\",\"_asset\":\"ERC20 token to withdraw.\",\"_to\":\"Address to receive the ERC20 balance.\"}},\"withdrawERC721(address,address,uint256)\":{\"params\":{\"_asset\":\"ERC721 token to withdraw.\",\"_id\":\"Token ID of the ERC721 token to withdraw.\",\"_to\":\"Address to receive the ERC721 token.\"}},\"withdrawETH(address)\":{\"params\":{\"_to\":\"Address to receive the ETH balance.\"}},\"withdrawETH(address,uint256)\":{\"params\":{\"_amount\":\"Amount of ETH to withdraw.\",\"_to\":\"Address to receive the ETH balance.\"}}},\"title\":\"AssetReceiver\",\"version\":1},\"userdoc\":{\"events\":{\"ReceivedETH(address,uint256)\":{\"notice\":\"Emitted when ETH is received by this address.\"},\"WithdrewERC20(address,address,address,uint256)\":{\"notice\":\"Emitted when ERC20 tokens are withdrawn from this address.\"},\"WithdrewERC721(address,address,address,uint256)\":{\"notice\":\"Emitted when ERC721 tokens are withdrawn from this address.\"},\"WithdrewETH(address,address,uint256)\":{\"notice\":\"Emitted when ETH is withdrawn from this address.\"}},\"kind\":\"user\",\"methods\":{\"CALL(address,bytes,uint256,uint256)\":{\"notice\":\"Sends a CALL to a target address.\"},\"DELEGATECALL(address,bytes,uint256)\":{\"notice\":\"Sends a DELEGATECALL to a target address.\"},\"withdrawERC20(address,address)\":{\"notice\":\"Withdraws full ERC20 balance to the recipient.\"},\"withdrawERC20(address,address,uint256)\":{\"notice\":\"Withdraws partial ERC20 balance to the recipient.\"},\"withdrawERC721(address,address,uint256)\":{\"notice\":\"Withdraws ERC721 token to the recipient.\"},\"withdrawETH(address)\":{\"notice\":\"Withdraws full ETH balance to the recipient.\"},\"withdrawETH(address,uint256)\":{\"notice\":\"Withdraws partial ETH balance to the recipient.\"}},\"notice\":\"AssetReceiver is a minimal contract for receiving funds assets in the form of either ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/AssetReceiver.sol\":\"AssetReceiver\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"@rari-capital/solmate/src/auth/Owned.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Simple single owner authorization mixin.\\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\\nabstract contract Owned {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event OwnerUpdated(address indexed user, address indexed newOwner);\\n\\n /*//////////////////////////////////////////////////////////////\\n OWNERSHIP STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n address public owner;\\n\\n modifier onlyOwner() virtual {\\n require(msg.sender == owner, \\\"UNAUTHORIZED\\\");\\n\\n _;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(address _owner) {\\n owner = _owner;\\n\\n emit OwnerUpdated(address(0), _owner);\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n OWNERSHIP LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function setOwner(address newOwner) public virtual onlyOwner {\\n owner = newOwner;\\n\\n emit OwnerUpdated(msg.sender, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x7e91c80b0dd1a14a19cb9e661b99924043adab6d9d893bbfcf3a6a3dc23a6743\",\"license\":\"AGPL-3.0-only\"},\"@rari-capital/solmate/src/tokens/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\\nabstract contract ERC20 {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n\\n /*//////////////////////////////////////////////////////////////\\n METADATA STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n string public name;\\n\\n string public symbol;\\n\\n uint8 public immutable decimals;\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 public totalSupply;\\n\\n mapping(address => uint256) public balanceOf;\\n\\n mapping(address => mapping(address => uint256)) public allowance;\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 internal immutable INITIAL_CHAIN_ID;\\n\\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\\n\\n mapping(address => uint256) public nonces;\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(\\n string memory _name,\\n string memory _symbol,\\n uint8 _decimals\\n ) {\\n name = _name;\\n symbol = _symbol;\\n decimals = _decimals;\\n\\n INITIAL_CHAIN_ID = block.chainid;\\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function approve(address spender, uint256 amount) public virtual returns (bool) {\\n allowance[msg.sender][spender] = amount;\\n\\n emit Approval(msg.sender, spender, amount);\\n\\n return true;\\n }\\n\\n function transfer(address to, uint256 amount) public virtual returns (bool) {\\n balanceOf[msg.sender] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(msg.sender, to, amount);\\n\\n return true;\\n }\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual returns (bool) {\\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\\n\\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\\n\\n balanceOf[from] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n return true;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public virtual {\\n require(deadline >= block.timestamp, \\\"PERMIT_DEADLINE_EXPIRED\\\");\\n\\n // Unchecked because the only math done is incrementing\\n // the owner's nonce which cannot realistically overflow.\\n unchecked {\\n address recoveredAddress = ecrecover(\\n keccak256(\\n abi.encodePacked(\\n \\\"\\\\x19\\\\x01\\\",\\n DOMAIN_SEPARATOR(),\\n keccak256(\\n abi.encode(\\n keccak256(\\n \\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\"\\n ),\\n owner,\\n spender,\\n value,\\n nonces[owner]++,\\n deadline\\n )\\n )\\n )\\n ),\\n v,\\n r,\\n s\\n );\\n\\n require(recoveredAddress != address(0) && recoveredAddress == owner, \\\"INVALID_SIGNER\\\");\\n\\n allowance[recoveredAddress][spender] = value;\\n }\\n\\n emit Approval(owner, spender, value);\\n }\\n\\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\\n }\\n\\n function computeDomainSeparator() internal view virtual returns (bytes32) {\\n return\\n keccak256(\\n abi.encode(\\n keccak256(\\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"),\\n keccak256(bytes(name)),\\n keccak256(\\\"1\\\"),\\n block.chainid,\\n address(this)\\n )\\n );\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL MINT/BURN LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _mint(address to, uint256 amount) internal virtual {\\n totalSupply += amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(address(0), to, amount);\\n }\\n\\n function _burn(address from, uint256 amount) internal virtual {\\n balanceOf[from] -= amount;\\n\\n // Cannot underflow because a user's balance\\n // will never be larger than the total supply.\\n unchecked {\\n totalSupply -= amount;\\n }\\n\\n emit Transfer(from, address(0), amount);\\n }\\n}\\n\",\"keccak256\":\"0x0240f7703cff32a61ee3e9fbb339e09a944260432a9ef37debf3692b1a6c8049\",\"license\":\"AGPL-3.0-only\"},\"@rari-capital/solmate/src/tokens/ERC721.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\\nabstract contract ERC721 {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\\n\\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\\n\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /*//////////////////////////////////////////////////////////////\\n METADATA STORAGE/LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n string public name;\\n\\n string public symbol;\\n\\n function tokenURI(uint256 id) public view virtual returns (string memory);\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC721 BALANCE/OWNER STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n mapping(uint256 => address) internal _ownerOf;\\n\\n mapping(address => uint256) internal _balanceOf;\\n\\n function ownerOf(uint256 id) public view virtual returns (address owner) {\\n require((owner = _ownerOf[id]) != address(0), \\\"NOT_MINTED\\\");\\n }\\n\\n function balanceOf(address owner) public view virtual returns (uint256) {\\n require(owner != address(0), \\\"ZERO_ADDRESS\\\");\\n\\n return _balanceOf[owner];\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC721 APPROVAL STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n mapping(uint256 => address) public getApproved;\\n\\n mapping(address => mapping(address => bool)) public isApprovedForAll;\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(string memory _name, string memory _symbol) {\\n name = _name;\\n symbol = _symbol;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC721 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function approve(address spender, uint256 id) public virtual {\\n address owner = _ownerOf[id];\\n\\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \\\"NOT_AUTHORIZED\\\");\\n\\n getApproved[id] = spender;\\n\\n emit Approval(owner, spender, id);\\n }\\n\\n function setApprovalForAll(address operator, bool approved) public virtual {\\n isApprovedForAll[msg.sender][operator] = approved;\\n\\n emit ApprovalForAll(msg.sender, operator, approved);\\n }\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 id\\n ) public virtual {\\n require(from == _ownerOf[id], \\\"WRONG_FROM\\\");\\n\\n require(to != address(0), \\\"INVALID_RECIPIENT\\\");\\n\\n require(\\n msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\\n \\\"NOT_AUTHORIZED\\\"\\n );\\n\\n // Underflow of the sender's balance is impossible because we check for\\n // ownership above and the recipient's balance can't realistically overflow.\\n unchecked {\\n _balanceOf[from]--;\\n\\n _balanceOf[to]++;\\n }\\n\\n _ownerOf[id] = to;\\n\\n delete getApproved[id];\\n\\n emit Transfer(from, to, id);\\n }\\n\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id\\n ) public virtual {\\n transferFrom(from, to, id);\\n\\n require(\\n to.code.length == 0 ||\\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \\\"\\\") ==\\n ERC721TokenReceiver.onERC721Received.selector,\\n \\\"UNSAFE_RECIPIENT\\\"\\n );\\n }\\n\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n bytes calldata data\\n ) public virtual {\\n transferFrom(from, to, id);\\n\\n require(\\n to.code.length == 0 ||\\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\\n ERC721TokenReceiver.onERC721Received.selector,\\n \\\"UNSAFE_RECIPIENT\\\"\\n );\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC165 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\\n return\\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL MINT/BURN LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _mint(address to, uint256 id) internal virtual {\\n require(to != address(0), \\\"INVALID_RECIPIENT\\\");\\n\\n require(_ownerOf[id] == address(0), \\\"ALREADY_MINTED\\\");\\n\\n // Counter overflow is incredibly unrealistic.\\n unchecked {\\n _balanceOf[to]++;\\n }\\n\\n _ownerOf[id] = to;\\n\\n emit Transfer(address(0), to, id);\\n }\\n\\n function _burn(uint256 id) internal virtual {\\n address owner = _ownerOf[id];\\n\\n require(owner != address(0), \\\"NOT_MINTED\\\");\\n\\n // Ownership check above ensures no underflow.\\n unchecked {\\n _balanceOf[owner]--;\\n }\\n\\n delete _ownerOf[id];\\n\\n delete getApproved[id];\\n\\n emit Transfer(owner, address(0), id);\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL SAFE MINT LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _safeMint(address to, uint256 id) internal virtual {\\n _mint(to, id);\\n\\n require(\\n to.code.length == 0 ||\\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \\\"\\\") ==\\n ERC721TokenReceiver.onERC721Received.selector,\\n \\\"UNSAFE_RECIPIENT\\\"\\n );\\n }\\n\\n function _safeMint(\\n address to,\\n uint256 id,\\n bytes memory data\\n ) internal virtual {\\n _mint(to, id);\\n\\n require(\\n to.code.length == 0 ||\\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\\n ERC721TokenReceiver.onERC721Received.selector,\\n \\\"UNSAFE_RECIPIENT\\\"\\n );\\n }\\n}\\n\\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\\nabstract contract ERC721TokenReceiver {\\n function onERC721Received(\\n address,\\n address,\\n uint256,\\n bytes calldata\\n ) external virtual returns (bytes4) {\\n return ERC721TokenReceiver.onERC721Received.selector;\\n }\\n}\\n\",\"keccak256\":\"0xb59c7c25eca386f39da4819a9f70f89b73b7583d5f5127a83ffe5339800b1183\",\"license\":\"AGPL-3.0-only\"},\"contracts/universal/AssetReceiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { ERC20 } from \\\"@rari-capital/solmate/src/tokens/ERC20.sol\\\";\\nimport { ERC721 } from \\\"@rari-capital/solmate/src/tokens/ERC721.sol\\\";\\nimport { Transactor } from \\\"./Transactor.sol\\\";\\n\\n/**\\n * @title AssetReceiver\\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\\n */\\ncontract AssetReceiver is Transactor {\\n /**\\n * Emitted when ETH is received by this address.\\n */\\n event ReceivedETH(address indexed from, uint256 amount);\\n\\n /**\\n * Emitted when ETH is withdrawn from this address.\\n */\\n event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\\n\\n /**\\n * Emitted when ERC20 tokens are withdrawn from this address.\\n */\\n event WithdrewERC20(\\n address indexed withdrawer,\\n address indexed recipient,\\n address indexed asset,\\n uint256 amount\\n );\\n\\n /**\\n * Emitted when ERC721 tokens are withdrawn from this address.\\n */\\n event WithdrewERC721(\\n address indexed withdrawer,\\n address indexed recipient,\\n address indexed asset,\\n uint256 id\\n );\\n\\n /**\\n * @param _owner Initial contract owner.\\n */\\n constructor(address _owner) Transactor(_owner) {}\\n\\n /**\\n * Make sure we can receive ETH.\\n */\\n receive() external payable {\\n emit ReceivedETH(msg.sender, msg.value);\\n }\\n\\n /**\\n * Withdraws full ETH balance to the recipient.\\n *\\n * @param _to Address to receive the ETH balance.\\n */\\n function withdrawETH(address payable _to) external onlyOwner {\\n withdrawETH(_to, address(this).balance);\\n }\\n\\n /**\\n * Withdraws partial ETH balance to the recipient.\\n *\\n * @param _to Address to receive the ETH balance.\\n * @param _amount Amount of ETH to withdraw.\\n */\\n function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\\n // slither-disable-next-line reentrancy-unlimited-gas\\n _to.transfer(_amount);\\n emit WithdrewETH(msg.sender, _to, _amount);\\n }\\n\\n /**\\n * Withdraws full ERC20 balance to the recipient.\\n *\\n * @param _asset ERC20 token to withdraw.\\n * @param _to Address to receive the ERC20 balance.\\n */\\n function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\\n withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\\n }\\n\\n /**\\n * Withdraws partial ERC20 balance to the recipient.\\n *\\n * @param _asset ERC20 token to withdraw.\\n * @param _to Address to receive the ERC20 balance.\\n * @param _amount Amount of ERC20 to withdraw.\\n */\\n function withdrawERC20(\\n ERC20 _asset,\\n address _to,\\n uint256 _amount\\n ) public onlyOwner {\\n // slither-disable-next-line unchecked-transfer\\n _asset.transfer(_to, _amount);\\n // slither-disable-next-line reentrancy-events\\n emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\\n }\\n\\n /**\\n * Withdraws ERC721 token to the recipient.\\n *\\n * @param _asset ERC721 token to withdraw.\\n * @param _to Address to receive the ERC721 token.\\n * @param _id Token ID of the ERC721 token to withdraw.\\n */\\n function withdrawERC721(\\n ERC721 _asset,\\n address _to,\\n uint256 _id\\n ) external onlyOwner {\\n _asset.transferFrom(address(this), _to, _id);\\n // slither-disable-next-line reentrancy-events\\n emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\\n }\\n}\\n\",\"keccak256\":\"0x1f82aff6f4e5a4bebebbfb4a2e0e4378ef9bc5bee8b81f88b27fc0ce73546d5f\",\"license\":\"MIT\"},\"contracts/universal/Transactor.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { Owned } from \\\"@rari-capital/solmate/src/auth/Owned.sol\\\";\\n\\n/**\\n * @title Transactor\\n * @notice Transactor is a minimal contract that can send transactions.\\n */\\ncontract Transactor is Owned {\\n /**\\n * @param _owner Initial contract owner.\\n */\\n constructor(address _owner) Owned(_owner) {}\\n\\n /**\\n * Sends a CALL to a target address.\\n *\\n * @param _target Address to call.\\n * @param _data Data to send with the call.\\n * @param _gas Amount of gas to send with the call.\\n * @param _value ETH value to send with the call.\\n * @return Boolean success value.\\n * @return Bytes data returned by the call.\\n */\\n function CALL(\\n address _target,\\n bytes memory _data,\\n uint256 _gas,\\n uint256 _value\\n ) external payable onlyOwner returns (bool, bytes memory) {\\n return _target.call{ gas: _gas, value: _value }(_data);\\n }\\n\\n /**\\n * Sends a DELEGATECALL to a target address.\\n *\\n * @param _target Address to call.\\n * @param _data Data to send with the call.\\n * @param _gas Amount of gas to send with the call.\\n * @return Boolean success value.\\n * @return Bytes data returned by the call.\\n */\\n function DELEGATECALL(\\n address _target,\\n bytes memory _data,\\n uint256 _gas\\n ) external payable onlyOwner returns (bool, bytes memory) {\\n // slither-disable-next-line controlled-delegatecall\\n return _target.delegatecall{ gas: _gas }(_data);\\n }\\n}\\n\",\"keccak256\":\"0xfe0d9c05a423d36775047e3285f76b874f8b887444d412a0d680c302c3b06a50\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b50604051610f6e380380610f6e83398101604081905261002f91610081565b600080546001600160a01b0319166001600160a01b038316908117825560405183928392917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a35050506100b1565b60006020828403121561009357600080fd5b81516001600160a01b03811681146100aa57600080fd5b9392505050565b610eae806100c06000396000f3fe60806040526004361061009a5760003560e01c80635cef8b4a116100695780638da5cb5b1161004e5780638da5cb5b146101a75780639456fbcc146101f95780639e73dbea1461021957600080fd5b80635cef8b4a1461015d578063690d83201461018757600080fd5b806313af4035146100db5780634025feb2146100fd57806344004cc11461011d5780634782f7791461013d57600080fd5b366100d65760405134815233907f4103257eaac983ca79a70d28f90dfc4fa16b619bb0c17ee7cab0d4034c2796249060200160405180910390a2005b600080fd5b3480156100e757600080fd5b506100fb6100f6366004610b3a565b61022c565b005b34801561010957600080fd5b506100fb610118366004610b5e565b610322565b34801561012957600080fd5b506100fb610138366004610b5e565b6104b4565b34801561014957600080fd5b506100fb610158366004610b9f565b610654565b61017061016b366004610ca5565b61076a565b60405161017e929190610d2e565b60405180910390f35b34801561019357600080fd5b506100fb6101a2366004610b3a565b610863565b3480156101b357600080fd5b506000546101d49073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161017e565b34801561020557600080fd5b506100fb610214366004610d88565b6108f1565b610170610227366004610dc1565b610a1b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152604482018390528416906323b872dd90606401600060405180830381600087803b15801561041957600080fd5b505af115801561042d573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f30b478a5e196e55886228aa87ba74a7dfeba655e0a4d7ba275eabfc22aabb7a8846040516104a791815260200190565b60405180910390a4505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526024820183905284169063a9059cbb90604401602060405180830381600087803b1580156105a557600080fd5b505af11580156105b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105dd9190610e21565b508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f6b00f1c7883f053ba83e907fd1965b22fffe3c4111383e725f04638a566cdbfa846040516104a791815260200190565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b60405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610718573d6000803e3d6000fd5b5060405181815273ffffffffffffffffffffffffffffffffffffffff83169033907f1f12aa8b6d492dd9b98e2b00b0b20830c2a7ded65afac13b60d169a034ae90bc9060200160405180910390a35050565b6000805460609073ffffffffffffffffffffffffffffffffffffffff1633146107ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b8473ffffffffffffffffffffffffffffffffffffffff1683856040516108159190610e43565b6000604051808303818686f4925050503d8060008114610851576040519150601f19603f3d011682016040523d82523d6000602084013e610856565b606091505b5091509150935093915050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146108e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b6108ee8147610654565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610972576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152610a17908390839073ffffffffffffffffffffffffffffffffffffffff8316906370a082319060240160206040518083038186803b1580156109df57600080fd5b505afa1580156109f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101389190610e5f565b5050565b6000805460609073ffffffffffffffffffffffffffffffffffffffff163314610aa0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b8573ffffffffffffffffffffffffffffffffffffffff16848487604051610ac79190610e43565b600060405180830381858888f193505050503d8060008114610b05576040519150601f19603f3d011682016040523d82523d6000602084013e610b0a565b606091505b509150915094509492505050565b73ffffffffffffffffffffffffffffffffffffffff811681146108ee57600080fd5b600060208284031215610b4c57600080fd5b8135610b5781610b18565b9392505050565b600080600060608486031215610b7357600080fd5b8335610b7e81610b18565b92506020840135610b8e81610b18565b929592945050506040919091013590565b60008060408385031215610bb257600080fd5b8235610bbd81610b18565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112610c0b57600080fd5b813567ffffffffffffffff80821115610c2657610c26610bcb565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715610c6c57610c6c610bcb565b81604052838152866020858801011115610c8557600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600060608486031215610cba57600080fd5b8335610cc581610b18565b9250602084013567ffffffffffffffff811115610ce157600080fd5b610ced86828701610bfa565b925050604084013590509250925092565b60005b83811015610d19578181015183820152602001610d01565b83811115610d28576000848401525b50505050565b82151581526040602082015260008251806040840152610d55816060850160208701610cfe565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016060019392505050565b60008060408385031215610d9b57600080fd5b8235610da681610b18565b91506020830135610db681610b18565b809150509250929050565b60008060008060808587031215610dd757600080fd5b8435610de281610b18565b9350602085013567ffffffffffffffff811115610dfe57600080fd5b610e0a87828801610bfa565b949794965050505060408301359260600135919050565b600060208284031215610e3357600080fd5b81518015158114610b5757600080fd5b60008251610e55818460208701610cfe565b9190910192915050565b600060208284031215610e7157600080fd5b505191905056fea2646970667358221220a79fda18860baa011a378f2e4963a1c9eb8fa5184c5fd3130308ce3c35ba96da64736f6c63430008090033",
"deployedBytecode": "0x60806040526004361061009a5760003560e01c80635cef8b4a116100695780638da5cb5b1161004e5780638da5cb5b146101a75780639456fbcc146101f95780639e73dbea1461021957600080fd5b80635cef8b4a1461015d578063690d83201461018757600080fd5b806313af4035146100db5780634025feb2146100fd57806344004cc11461011d5780634782f7791461013d57600080fd5b366100d65760405134815233907f4103257eaac983ca79a70d28f90dfc4fa16b619bb0c17ee7cab0d4034c2796249060200160405180910390a2005b600080fd5b3480156100e757600080fd5b506100fb6100f6366004610b3a565b61022c565b005b34801561010957600080fd5b506100fb610118366004610b5e565b610322565b34801561012957600080fd5b506100fb610138366004610b5e565b6104b4565b34801561014957600080fd5b506100fb610158366004610b9f565b610654565b61017061016b366004610ca5565b61076a565b60405161017e929190610d2e565b60405180910390f35b34801561019357600080fd5b506100fb6101a2366004610b3a565b610863565b3480156101b357600080fd5b506000546101d49073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161017e565b34801561020557600080fd5b506100fb610214366004610d88565b6108f1565b610170610227366004610dc1565b610a1b565b60005473ffffffffffffffffffffffffffffffffffffffff1633146102b2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103a3576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152604482018390528416906323b872dd90606401600060405180830381600087803b15801561041957600080fd5b505af115801561042d573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f30b478a5e196e55886228aa87ba74a7dfeba655e0a4d7ba275eabfc22aabb7a8846040516104a791815260200190565b60405180910390a4505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610535576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526024820183905284169063a9059cbb90604401602060405180830381600087803b1580156105a557600080fd5b505af11580156105b9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105dd9190610e21565b508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f6b00f1c7883f053ba83e907fd1965b22fffe3c4111383e725f04638a566cdbfa846040516104a791815260200190565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106d5576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b60405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f19350505050158015610718573d6000803e3d6000fd5b5060405181815273ffffffffffffffffffffffffffffffffffffffff83169033907f1f12aa8b6d492dd9b98e2b00b0b20830c2a7ded65afac13b60d169a034ae90bc9060200160405180910390a35050565b6000805460609073ffffffffffffffffffffffffffffffffffffffff1633146107ef576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b8473ffffffffffffffffffffffffffffffffffffffff1683856040516108159190610e43565b6000604051808303818686f4925050503d8060008114610851576040519150601f19603f3d011682016040523d82523d6000602084013e610856565b606091505b5091509150935093915050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146108e4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b6108ee8147610654565b50565b60005473ffffffffffffffffffffffffffffffffffffffff163314610972576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152610a17908390839073ffffffffffffffffffffffffffffffffffffffff8316906370a082319060240160206040518083038186803b1580156109df57600080fd5b505afa1580156109f3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906101389190610e5f565b5050565b6000805460609073ffffffffffffffffffffffffffffffffffffffff163314610aa0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016102a9565b8573ffffffffffffffffffffffffffffffffffffffff16848487604051610ac79190610e43565b600060405180830381858888f193505050503d8060008114610b05576040519150601f19603f3d011682016040523d82523d6000602084013e610b0a565b606091505b509150915094509492505050565b73ffffffffffffffffffffffffffffffffffffffff811681146108ee57600080fd5b600060208284031215610b4c57600080fd5b8135610b5781610b18565b9392505050565b600080600060608486031215610b7357600080fd5b8335610b7e81610b18565b92506020840135610b8e81610b18565b929592945050506040919091013590565b60008060408385031215610bb257600080fd5b8235610bbd81610b18565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f830112610c0b57600080fd5b813567ffffffffffffffff80821115610c2657610c26610bcb565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908282118183101715610c6c57610c6c610bcb565b81604052838152866020858801011115610c8557600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600060608486031215610cba57600080fd5b8335610cc581610b18565b9250602084013567ffffffffffffffff811115610ce157600080fd5b610ced86828701610bfa565b925050604084013590509250925092565b60005b83811015610d19578181015183820152602001610d01565b83811115610d28576000848401525b50505050565b82151581526040602082015260008251806040840152610d55816060850160208701610cfe565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016919091016060019392505050565b60008060408385031215610d9b57600080fd5b8235610da681610b18565b91506020830135610db681610b18565b809150509250929050565b60008060008060808587031215610dd757600080fd5b8435610de281610b18565b9350602085013567ffffffffffffffff811115610dfe57600080fd5b610e0a87828801610bfa565b949794965050505060408301359260600135919050565b600060208284031215610e3357600080fd5b81518015158114610b5757600080fd5b60008251610e55818460208701610cfe565b9190910192915050565b600060208284031215610e7157600080fd5b505191905056fea2646970667358221220a79fda18860baa011a378f2e4963a1c9eb8fa5184c5fd3130308ce3c35ba96da64736f6c63430008090033",
"devdoc": {
"kind": "dev",
"methods": {
"CALL(address,bytes,uint256,uint256)": {
"params": {
"_data": "Data to send with the call.",
"_gas": "Amount of gas to send with the call.",
"_target": "Address to call.",
"_value": "ETH value to send with the call."
},
"returns": {
"_0": "Boolean success value.",
"_1": "Bytes data returned by the call."
}
},
"DELEGATECALL(address,bytes,uint256)": {
"params": {
"_data": "Data to send with the call.",
"_gas": "Amount of gas to send with the call.",
"_target": "Address to call."
},
"returns": {
"_0": "Boolean success value.",
"_1": "Bytes data returned by the call."
}
},
"constructor": {
"params": {
"_owner": "Initial contract owner."
}
},
"withdrawERC20(address,address)": {
"params": {
"_asset": "ERC20 token to withdraw.",
"_to": "Address to receive the ERC20 balance."
}
},
"withdrawERC20(address,address,uint256)": {
"params": {
"_amount": "Amount of ERC20 to withdraw.",
"_asset": "ERC20 token to withdraw.",
"_to": "Address to receive the ERC20 balance."
}
},
"withdrawERC721(address,address,uint256)": {
"params": {
"_asset": "ERC721 token to withdraw.",
"_id": "Token ID of the ERC721 token to withdraw.",
"_to": "Address to receive the ERC721 token."
}
},
"withdrawETH(address)": {
"params": {
"_to": "Address to receive the ETH balance."
}
},
"withdrawETH(address,uint256)": {
"params": {
"_amount": "Amount of ETH to withdraw.",
"_to": "Address to receive the ETH balance."
}
}
},
"title": "AssetReceiver",
"version": 1
},
"userdoc": {
"events": {
"ReceivedETH(address,uint256)": {
"notice": "Emitted when ETH is received by this address."
},
"WithdrewERC20(address,address,address,uint256)": {
"notice": "Emitted when ERC20 tokens are withdrawn from this address."
},
"WithdrewERC721(address,address,address,uint256)": {
"notice": "Emitted when ERC721 tokens are withdrawn from this address."
},
"WithdrewETH(address,address,uint256)": {
"notice": "Emitted when ETH is withdrawn from this address."
}
},
"kind": "user",
"methods": {
"CALL(address,bytes,uint256,uint256)": {
"notice": "Sends a CALL to a target address."
},
"DELEGATECALL(address,bytes,uint256)": {
"notice": "Sends a DELEGATECALL to a target address."
},
"withdrawERC20(address,address)": {
"notice": "Withdraws full ERC20 balance to the recipient."
},
"withdrawERC20(address,address,uint256)": {
"notice": "Withdraws partial ERC20 balance to the recipient."
},
"withdrawERC721(address,address,uint256)": {
"notice": "Withdraws ERC721 token to the recipient."
},
"withdrawETH(address)": {
"notice": "Withdraws full ETH balance to the recipient."
},
"withdrawETH(address,uint256)": {
"notice": "Withdraws partial ETH balance to the recipient."
}
},
"notice": "AssetReceiver is a minimal contract for receiving funds assets in the form of either ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.",
"version": 1
},
"storageLayout": {
"storage": [
{
"astId": 10,
"contract": "contracts/universal/AssetReceiver.sol:AssetReceiver",
"label": "owner",
"offset": 0,
"slot": "0",
"type": "t_address"
}
],
"types": {
"t_address": {
"encoding": "inplace",
"label": "address",
"numberOfBytes": "20"
}
}
}
}
\ No newline at end of file
{
"address": "0x78A25524D90E3D0596558fb43789bD800a5c3007",
"abi": [
{
"inputs": [
{
"internalType": "address",
"name": "_owner",
"type": "address"
}
],
"stateMutability": "nonpayable",
"type": "constructor"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "user",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "OwnerUpdated",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "from",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "ReceivedETH",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "withdrawer",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "asset",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "WithdrewERC20",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "withdrawer",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "asset",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "id",
"type": "uint256"
}
],
"name": "WithdrewERC721",
"type": "event"
},
{
"anonymous": false,
"inputs": [
{
"indexed": true,
"internalType": "address",
"name": "withdrawer",
"type": "address"
},
{
"indexed": true,
"internalType": "address",
"name": "recipient",
"type": "address"
},
{
"indexed": false,
"internalType": "uint256",
"name": "amount",
"type": "uint256"
}
],
"name": "WithdrewETH",
"type": "event"
},
{
"inputs": [
{
"internalType": "address",
"name": "_target",
"type": "address"
},
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "_gas",
"type": "uint256"
},
{
"internalType": "uint256",
"name": "_value",
"type": "uint256"
}
],
"name": "CALL",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_target",
"type": "address"
},
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
},
{
"internalType": "uint256",
"name": "_gas",
"type": "uint256"
}
],
"name": "DELEGATECALL",
"outputs": [
{
"internalType": "bool",
"name": "",
"type": "bool"
},
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"stateMutability": "payable",
"type": "function"
},
{
"inputs": [],
"name": "data",
"outputs": [
{
"internalType": "bytes",
"name": "",
"type": "bytes"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "owner",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [],
"name": "recipient",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "bytes",
"name": "_data",
"type": "bytes"
}
],
"name": "setData",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "newOwner",
"type": "address"
}
],
"name": "setOwner",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_recipient",
"type": "address"
}
],
"name": "setRecipient",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address",
"name": "_teleportr",
"type": "address"
}
],
"name": "setTeleportr",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "teleportr",
"outputs": [
{
"internalType": "address",
"name": "",
"type": "address"
}
],
"stateMutability": "view",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ERC20",
"name": "_asset",
"type": "address"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "withdrawERC20",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ERC20",
"name": "_asset",
"type": "address"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
}
],
"name": "withdrawERC20",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "contract ERC721",
"name": "_asset",
"type": "address"
},
{
"internalType": "address",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_id",
"type": "uint256"
}
],
"name": "withdrawERC721",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address payable",
"name": "_to",
"type": "address"
},
{
"internalType": "uint256",
"name": "_amount",
"type": "uint256"
}
],
"name": "withdrawETH",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [
{
"internalType": "address payable",
"name": "_to",
"type": "address"
}
],
"name": "withdrawETH",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"inputs": [],
"name": "withdrawFromTeleportr",
"outputs": [],
"stateMutability": "nonpayable",
"type": "function"
},
{
"stateMutability": "payable",
"type": "receive"
}
],
"transactionHash": "0xe7914c509af8b99ef3421601b487ccdf2c7ef5955ffbd58bbb7d786452df3638",
"receipt": {
"to": "0x4e59b44847b379578588920cA78FbF26c0B4956C",
"from": "0xc37f6a6c4AB335E20d10F034B90386E2fb70bbF5",
"contractAddress": null,
"transactionIndex": 249,
"gasUsed": "1233027",
"logsBloom": "0x00000000000000000001000000000000000000000000000000000000000000000000100000000000000000000000080000000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000080000000020000000000000000000800000000000080000000000000000000000000000000000000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000020000000000004000000020000000000000000000000000000000000000000000000",
"blockHash": "0xbdb85532b8a9423604350b1254f5b465838c92bffaecd1768cf94b95e58ffa80",
"transactionHash": "0xe7914c509af8b99ef3421601b487ccdf2c7ef5955ffbd58bbb7d786452df3638",
"logs": [
{
"transactionIndex": 249,
"blockNumber": 14981055,
"transactionHash": "0xe7914c509af8b99ef3421601b487ccdf2c7ef5955ffbd58bbb7d786452df3638",
"address": "0x78A25524D90E3D0596558fb43789bD800a5c3007",
"topics": [
"0x8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76",
"0x0000000000000000000000000000000000000000000000000000000000000000",
"0x0000000000000000000000009c6373de60c2d3297b18a8f964618ac46e011b58"
],
"data": "0x",
"logIndex": 574,
"blockHash": "0xbdb85532b8a9423604350b1254f5b465838c92bffaecd1768cf94b95e58ffa80"
}
],
"blockNumber": 14981055,
"cumulativeGasUsed": "26253070",
"status": 1,
"byzantium": true
},
"args": [
"0x9C6373dE60c2D3297b18A8f964618ac46E011B58"
],
"numDeployments": 1,
"solcInputHash": "b09909e91a3ff9823ceba49a3a845230",
"metadata": "{\"compiler\":{\"version\":\"0.8.9+commit.e5eed63a\"},\"language\":\"Solidity\",\"output\":{\"abi\":[{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_owner\",\"type\":\"address\"}],\"stateMutability\":\"nonpayable\",\"type\":\"constructor\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"user\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"OwnerUpdated\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"from\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"ReceivedETH\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrewERC20\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"asset\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"id\",\"type\":\"uint256\"}],\"name\":\"WithdrewERC721\",\"type\":\"event\"},{\"anonymous\":false,\"inputs\":[{\"indexed\":true,\"internalType\":\"address\",\"name\":\"withdrawer\",\"type\":\"address\"},{\"indexed\":true,\"internalType\":\"address\",\"name\":\"recipient\",\"type\":\"address\"},{\"indexed\":false,\"internalType\":\"uint256\",\"name\":\"amount\",\"type\":\"uint256\"}],\"name\":\"WithdrewETH\",\"type\":\"event\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gas\",\"type\":\"uint256\"},{\"internalType\":\"uint256\",\"name\":\"_value\",\"type\":\"uint256\"}],\"name\":\"CALL\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_target\",\"type\":\"address\"},{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"},{\"internalType\":\"uint256\",\"name\":\"_gas\",\"type\":\"uint256\"}],\"name\":\"DELEGATECALL\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"\",\"type\":\"bool\"},{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"payable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"data\",\"outputs\":[{\"internalType\":\"bytes\",\"name\":\"\",\"type\":\"bytes\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"owner\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"recipient\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"bytes\",\"name\":\"_data\",\"type\":\"bytes\"}],\"name\":\"setData\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"newOwner\",\"type\":\"address\"}],\"name\":\"setOwner\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_recipient\",\"type\":\"address\"}],\"name\":\"setRecipient\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"_teleportr\",\"type\":\"address\"}],\"name\":\"setTeleportr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"teleportr\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ERC20\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"}],\"name\":\"withdrawERC20\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"contract ERC721\",\"name\":\"_asset\",\"type\":\"address\"},{\"internalType\":\"address\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_id\",\"type\":\"uint256\"}],\"name\":\"withdrawERC721\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_to\",\"type\":\"address\"},{\"internalType\":\"uint256\",\"name\":\"_amount\",\"type\":\"uint256\"}],\"name\":\"withdrawETH\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address payable\",\"name\":\"_to\",\"type\":\"address\"}],\"name\":\"withdrawETH\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"withdrawFromTeleportr\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"stateMutability\":\"payable\",\"type\":\"receive\"}],\"devdoc\":{\"kind\":\"dev\",\"methods\":{\"CALL(address,bytes,uint256,uint256)\":{\"params\":{\"_data\":\"Data to send with the call.\",\"_gas\":\"Amount of gas to send with the call.\",\"_target\":\"Address to call.\",\"_value\":\"ETH value to send with the call.\"},\"returns\":{\"_0\":\"Boolean success value.\",\"_1\":\"Bytes data returned by the call.\"}},\"DELEGATECALL(address,bytes,uint256)\":{\"params\":{\"_data\":\"Data to send with the call.\",\"_gas\":\"Amount of gas to send with the call.\",\"_target\":\"Address to call.\"},\"returns\":{\"_0\":\"Boolean success value.\",\"_1\":\"Bytes data returned by the call.\"}},\"constructor\":{\"params\":{\"_owner\":\"Initial owner of the contract.\"}},\"setData(bytes)\":{\"params\":{\"_data\":\"New data to be sent to the recipient address.\"}},\"setRecipient(address)\":{\"params\":{\"_recipient\":\"New recipient address.\"}},\"setTeleportr(address)\":{\"params\":{\"_teleportr\":\"New Teleportr contract address.\"}},\"withdrawERC20(address,address)\":{\"params\":{\"_asset\":\"ERC20 token to withdraw.\",\"_to\":\"Address to receive the ERC20 balance.\"}},\"withdrawERC20(address,address,uint256)\":{\"params\":{\"_amount\":\"Amount of ERC20 to withdraw.\",\"_asset\":\"ERC20 token to withdraw.\",\"_to\":\"Address to receive the ERC20 balance.\"}},\"withdrawERC721(address,address,uint256)\":{\"params\":{\"_asset\":\"ERC721 token to withdraw.\",\"_id\":\"Token ID of the ERC721 token to withdraw.\",\"_to\":\"Address to receive the ERC721 token.\"}},\"withdrawETH(address)\":{\"params\":{\"_to\":\"Address to receive the ETH balance.\"}},\"withdrawETH(address,uint256)\":{\"params\":{\"_amount\":\"Amount of ETH to withdraw.\",\"_to\":\"Address to receive the ETH balance.\"}}},\"title\":\"TeleportrWithdrawer\",\"version\":1},\"userdoc\":{\"events\":{\"ReceivedETH(address,uint256)\":{\"notice\":\"Emitted when ETH is received by this address.\"},\"WithdrewERC20(address,address,address,uint256)\":{\"notice\":\"Emitted when ERC20 tokens are withdrawn from this address.\"},\"WithdrewERC721(address,address,address,uint256)\":{\"notice\":\"Emitted when ERC721 tokens are withdrawn from this address.\"},\"WithdrewETH(address,address,uint256)\":{\"notice\":\"Emitted when ETH is withdrawn from this address.\"}},\"kind\":\"user\",\"methods\":{\"CALL(address,bytes,uint256,uint256)\":{\"notice\":\"Sends a CALL to a target address.\"},\"DELEGATECALL(address,bytes,uint256)\":{\"notice\":\"Sends a DELEGATECALL to a target address.\"},\"data()\":{\"notice\":\"Data to be sent to the recipient address.\"},\"recipient()\":{\"notice\":\"Address that will receive Teleportr withdrawals.\"},\"setData(bytes)\":{\"notice\":\"Allows the owner to update the data to be sent to the recipient address.\"},\"setRecipient(address)\":{\"notice\":\"Allows the owner to update the recipient address.\"},\"setTeleportr(address)\":{\"notice\":\"Allows the owner to update the Teleportr contract address.\"},\"teleportr()\":{\"notice\":\"Address of the Teleportr contract.\"},\"withdrawERC20(address,address)\":{\"notice\":\"Withdraws full ERC20 balance to the recipient.\"},\"withdrawERC20(address,address,uint256)\":{\"notice\":\"Withdraws partial ERC20 balance to the recipient.\"},\"withdrawERC721(address,address,uint256)\":{\"notice\":\"Withdraws ERC721 token to the recipient.\"},\"withdrawETH(address)\":{\"notice\":\"Withdraws full ETH balance to the recipient.\"},\"withdrawETH(address,uint256)\":{\"notice\":\"Withdraws partial ETH balance to the recipient.\"},\"withdrawFromTeleportr()\":{\"notice\":\"Withdraws the full balance of the Teleportr contract to the recipient address. Anyone is allowed to trigger this function since the recipient address cannot be controlled by the msg.sender.\"}},\"notice\":\"The TeleportrWithdrawer is a simple contract capable of withdrawing funds from the TeleportrContract and sending them to some recipient address.\",\"version\":1}},\"settings\":{\"compilationTarget\":{\"contracts/universal/TeleportrWithdrawer.sol\":\"TeleportrWithdrawer\"},\"evmVersion\":\"london\",\"libraries\":{},\"metadata\":{\"bytecodeHash\":\"ipfs\",\"useLiteralContent\":true},\"optimizer\":{\"enabled\":true,\"runs\":10000},\"remappings\":[]},\"sources\":{\"@rari-capital/solmate/src/auth/Owned.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Simple single owner authorization mixin.\\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\\nabstract contract Owned {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event OwnerUpdated(address indexed user, address indexed newOwner);\\n\\n /*//////////////////////////////////////////////////////////////\\n OWNERSHIP STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n address public owner;\\n\\n modifier onlyOwner() virtual {\\n require(msg.sender == owner, \\\"UNAUTHORIZED\\\");\\n\\n _;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(address _owner) {\\n owner = _owner;\\n\\n emit OwnerUpdated(address(0), _owner);\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n OWNERSHIP LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function setOwner(address newOwner) public virtual onlyOwner {\\n owner = newOwner;\\n\\n emit OwnerUpdated(msg.sender, newOwner);\\n }\\n}\\n\",\"keccak256\":\"0x7e91c80b0dd1a14a19cb9e661b99924043adab6d9d893bbfcf3a6a3dc23a6743\",\"license\":\"AGPL-3.0-only\"},\"@rari-capital/solmate/src/tokens/ERC20.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\\nabstract contract ERC20 {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event Transfer(address indexed from, address indexed to, uint256 amount);\\n\\n event Approval(address indexed owner, address indexed spender, uint256 amount);\\n\\n /*//////////////////////////////////////////////////////////////\\n METADATA STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n string public name;\\n\\n string public symbol;\\n\\n uint8 public immutable decimals;\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 public totalSupply;\\n\\n mapping(address => uint256) public balanceOf;\\n\\n mapping(address => mapping(address => uint256)) public allowance;\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n uint256 internal immutable INITIAL_CHAIN_ID;\\n\\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\\n\\n mapping(address => uint256) public nonces;\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(\\n string memory _name,\\n string memory _symbol,\\n uint8 _decimals\\n ) {\\n name = _name;\\n symbol = _symbol;\\n decimals = _decimals;\\n\\n INITIAL_CHAIN_ID = block.chainid;\\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC20 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function approve(address spender, uint256 amount) public virtual returns (bool) {\\n allowance[msg.sender][spender] = amount;\\n\\n emit Approval(msg.sender, spender, amount);\\n\\n return true;\\n }\\n\\n function transfer(address to, uint256 amount) public virtual returns (bool) {\\n balanceOf[msg.sender] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(msg.sender, to, amount);\\n\\n return true;\\n }\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 amount\\n ) public virtual returns (bool) {\\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\\n\\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\\n\\n balanceOf[from] -= amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(from, to, amount);\\n\\n return true;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n EIP-2612 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function permit(\\n address owner,\\n address spender,\\n uint256 value,\\n uint256 deadline,\\n uint8 v,\\n bytes32 r,\\n bytes32 s\\n ) public virtual {\\n require(deadline >= block.timestamp, \\\"PERMIT_DEADLINE_EXPIRED\\\");\\n\\n // Unchecked because the only math done is incrementing\\n // the owner's nonce which cannot realistically overflow.\\n unchecked {\\n address recoveredAddress = ecrecover(\\n keccak256(\\n abi.encodePacked(\\n \\\"\\\\x19\\\\x01\\\",\\n DOMAIN_SEPARATOR(),\\n keccak256(\\n abi.encode(\\n keccak256(\\n \\\"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\\\"\\n ),\\n owner,\\n spender,\\n value,\\n nonces[owner]++,\\n deadline\\n )\\n )\\n )\\n ),\\n v,\\n r,\\n s\\n );\\n\\n require(recoveredAddress != address(0) && recoveredAddress == owner, \\\"INVALID_SIGNER\\\");\\n\\n allowance[recoveredAddress][spender] = value;\\n }\\n\\n emit Approval(owner, spender, value);\\n }\\n\\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\\n }\\n\\n function computeDomainSeparator() internal view virtual returns (bytes32) {\\n return\\n keccak256(\\n abi.encode(\\n keccak256(\\\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\\\"),\\n keccak256(bytes(name)),\\n keccak256(\\\"1\\\"),\\n block.chainid,\\n address(this)\\n )\\n );\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL MINT/BURN LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _mint(address to, uint256 amount) internal virtual {\\n totalSupply += amount;\\n\\n // Cannot overflow because the sum of all user\\n // balances can't exceed the max uint256 value.\\n unchecked {\\n balanceOf[to] += amount;\\n }\\n\\n emit Transfer(address(0), to, amount);\\n }\\n\\n function _burn(address from, uint256 amount) internal virtual {\\n balanceOf[from] -= amount;\\n\\n // Cannot underflow because a user's balance\\n // will never be larger than the total supply.\\n unchecked {\\n totalSupply -= amount;\\n }\\n\\n emit Transfer(from, address(0), amount);\\n }\\n}\\n\",\"keccak256\":\"0x0240f7703cff32a61ee3e9fbb339e09a944260432a9ef37debf3692b1a6c8049\",\"license\":\"AGPL-3.0-only\"},\"@rari-capital/solmate/src/tokens/ERC721.sol\":{\"content\":\"// SPDX-License-Identifier: AGPL-3.0-only\\npragma solidity >=0.8.0;\\n\\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\\nabstract contract ERC721 {\\n /*//////////////////////////////////////////////////////////////\\n EVENTS\\n //////////////////////////////////////////////////////////////*/\\n\\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\\n\\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\\n\\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\\n\\n /*//////////////////////////////////////////////////////////////\\n METADATA STORAGE/LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n string public name;\\n\\n string public symbol;\\n\\n function tokenURI(uint256 id) public view virtual returns (string memory);\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC721 BALANCE/OWNER STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n mapping(uint256 => address) internal _ownerOf;\\n\\n mapping(address => uint256) internal _balanceOf;\\n\\n function ownerOf(uint256 id) public view virtual returns (address owner) {\\n require((owner = _ownerOf[id]) != address(0), \\\"NOT_MINTED\\\");\\n }\\n\\n function balanceOf(address owner) public view virtual returns (uint256) {\\n require(owner != address(0), \\\"ZERO_ADDRESS\\\");\\n\\n return _balanceOf[owner];\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC721 APPROVAL STORAGE\\n //////////////////////////////////////////////////////////////*/\\n\\n mapping(uint256 => address) public getApproved;\\n\\n mapping(address => mapping(address => bool)) public isApprovedForAll;\\n\\n /*//////////////////////////////////////////////////////////////\\n CONSTRUCTOR\\n //////////////////////////////////////////////////////////////*/\\n\\n constructor(string memory _name, string memory _symbol) {\\n name = _name;\\n symbol = _symbol;\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC721 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function approve(address spender, uint256 id) public virtual {\\n address owner = _ownerOf[id];\\n\\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \\\"NOT_AUTHORIZED\\\");\\n\\n getApproved[id] = spender;\\n\\n emit Approval(owner, spender, id);\\n }\\n\\n function setApprovalForAll(address operator, bool approved) public virtual {\\n isApprovedForAll[msg.sender][operator] = approved;\\n\\n emit ApprovalForAll(msg.sender, operator, approved);\\n }\\n\\n function transferFrom(\\n address from,\\n address to,\\n uint256 id\\n ) public virtual {\\n require(from == _ownerOf[id], \\\"WRONG_FROM\\\");\\n\\n require(to != address(0), \\\"INVALID_RECIPIENT\\\");\\n\\n require(\\n msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\\n \\\"NOT_AUTHORIZED\\\"\\n );\\n\\n // Underflow of the sender's balance is impossible because we check for\\n // ownership above and the recipient's balance can't realistically overflow.\\n unchecked {\\n _balanceOf[from]--;\\n\\n _balanceOf[to]++;\\n }\\n\\n _ownerOf[id] = to;\\n\\n delete getApproved[id];\\n\\n emit Transfer(from, to, id);\\n }\\n\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id\\n ) public virtual {\\n transferFrom(from, to, id);\\n\\n require(\\n to.code.length == 0 ||\\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \\\"\\\") ==\\n ERC721TokenReceiver.onERC721Received.selector,\\n \\\"UNSAFE_RECIPIENT\\\"\\n );\\n }\\n\\n function safeTransferFrom(\\n address from,\\n address to,\\n uint256 id,\\n bytes calldata data\\n ) public virtual {\\n transferFrom(from, to, id);\\n\\n require(\\n to.code.length == 0 ||\\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\\n ERC721TokenReceiver.onERC721Received.selector,\\n \\\"UNSAFE_RECIPIENT\\\"\\n );\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n ERC165 LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\\n return\\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL MINT/BURN LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _mint(address to, uint256 id) internal virtual {\\n require(to != address(0), \\\"INVALID_RECIPIENT\\\");\\n\\n require(_ownerOf[id] == address(0), \\\"ALREADY_MINTED\\\");\\n\\n // Counter overflow is incredibly unrealistic.\\n unchecked {\\n _balanceOf[to]++;\\n }\\n\\n _ownerOf[id] = to;\\n\\n emit Transfer(address(0), to, id);\\n }\\n\\n function _burn(uint256 id) internal virtual {\\n address owner = _ownerOf[id];\\n\\n require(owner != address(0), \\\"NOT_MINTED\\\");\\n\\n // Ownership check above ensures no underflow.\\n unchecked {\\n _balanceOf[owner]--;\\n }\\n\\n delete _ownerOf[id];\\n\\n delete getApproved[id];\\n\\n emit Transfer(owner, address(0), id);\\n }\\n\\n /*//////////////////////////////////////////////////////////////\\n INTERNAL SAFE MINT LOGIC\\n //////////////////////////////////////////////////////////////*/\\n\\n function _safeMint(address to, uint256 id) internal virtual {\\n _mint(to, id);\\n\\n require(\\n to.code.length == 0 ||\\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \\\"\\\") ==\\n ERC721TokenReceiver.onERC721Received.selector,\\n \\\"UNSAFE_RECIPIENT\\\"\\n );\\n }\\n\\n function _safeMint(\\n address to,\\n uint256 id,\\n bytes memory data\\n ) internal virtual {\\n _mint(to, id);\\n\\n require(\\n to.code.length == 0 ||\\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\\n ERC721TokenReceiver.onERC721Received.selector,\\n \\\"UNSAFE_RECIPIENT\\\"\\n );\\n }\\n}\\n\\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\\nabstract contract ERC721TokenReceiver {\\n function onERC721Received(\\n address,\\n address,\\n uint256,\\n bytes calldata\\n ) external virtual returns (bytes4) {\\n return ERC721TokenReceiver.onERC721Received.selector;\\n }\\n}\\n\",\"keccak256\":\"0xb59c7c25eca386f39da4819a9f70f89b73b7583d5f5127a83ffe5339800b1183\",\"license\":\"AGPL-3.0-only\"},\"contracts/universal/AssetReceiver.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { ERC20 } from \\\"@rari-capital/solmate/src/tokens/ERC20.sol\\\";\\nimport { ERC721 } from \\\"@rari-capital/solmate/src/tokens/ERC721.sol\\\";\\nimport { Transactor } from \\\"./Transactor.sol\\\";\\n\\n/**\\n * @title AssetReceiver\\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\\n */\\ncontract AssetReceiver is Transactor {\\n /**\\n * Emitted when ETH is received by this address.\\n */\\n event ReceivedETH(address indexed from, uint256 amount);\\n\\n /**\\n * Emitted when ETH is withdrawn from this address.\\n */\\n event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\\n\\n /**\\n * Emitted when ERC20 tokens are withdrawn from this address.\\n */\\n event WithdrewERC20(\\n address indexed withdrawer,\\n address indexed recipient,\\n address indexed asset,\\n uint256 amount\\n );\\n\\n /**\\n * Emitted when ERC721 tokens are withdrawn from this address.\\n */\\n event WithdrewERC721(\\n address indexed withdrawer,\\n address indexed recipient,\\n address indexed asset,\\n uint256 id\\n );\\n\\n /**\\n * @param _owner Initial contract owner.\\n */\\n constructor(address _owner) Transactor(_owner) {}\\n\\n /**\\n * Make sure we can receive ETH.\\n */\\n receive() external payable {\\n emit ReceivedETH(msg.sender, msg.value);\\n }\\n\\n /**\\n * Withdraws full ETH balance to the recipient.\\n *\\n * @param _to Address to receive the ETH balance.\\n */\\n function withdrawETH(address payable _to) external onlyOwner {\\n withdrawETH(_to, address(this).balance);\\n }\\n\\n /**\\n * Withdraws partial ETH balance to the recipient.\\n *\\n * @param _to Address to receive the ETH balance.\\n * @param _amount Amount of ETH to withdraw.\\n */\\n function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\\n // slither-disable-next-line reentrancy-unlimited-gas\\n _to.transfer(_amount);\\n emit WithdrewETH(msg.sender, _to, _amount);\\n }\\n\\n /**\\n * Withdraws full ERC20 balance to the recipient.\\n *\\n * @param _asset ERC20 token to withdraw.\\n * @param _to Address to receive the ERC20 balance.\\n */\\n function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\\n withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\\n }\\n\\n /**\\n * Withdraws partial ERC20 balance to the recipient.\\n *\\n * @param _asset ERC20 token to withdraw.\\n * @param _to Address to receive the ERC20 balance.\\n * @param _amount Amount of ERC20 to withdraw.\\n */\\n function withdrawERC20(\\n ERC20 _asset,\\n address _to,\\n uint256 _amount\\n ) public onlyOwner {\\n // slither-disable-next-line unchecked-transfer\\n _asset.transfer(_to, _amount);\\n // slither-disable-next-line reentrancy-events\\n emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\\n }\\n\\n /**\\n * Withdraws ERC721 token to the recipient.\\n *\\n * @param _asset ERC721 token to withdraw.\\n * @param _to Address to receive the ERC721 token.\\n * @param _id Token ID of the ERC721 token to withdraw.\\n */\\n function withdrawERC721(\\n ERC721 _asset,\\n address _to,\\n uint256 _id\\n ) external onlyOwner {\\n _asset.transferFrom(address(this), _to, _id);\\n // slither-disable-next-line reentrancy-events\\n emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\\n }\\n}\\n\",\"keccak256\":\"0x1f82aff6f4e5a4bebebbfb4a2e0e4378ef9bc5bee8b81f88b27fc0ce73546d5f\",\"license\":\"MIT\"},\"contracts/universal/TeleportrWithdrawer.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { AssetReceiver } from \\\"./AssetReceiver.sol\\\";\\n\\n/**\\n * @notice Stub interface for Teleportr.\\n */\\ninterface Teleportr {\\n function withdrawBalance() external;\\n}\\n\\n/**\\n * @title TeleportrWithdrawer\\n * @notice The TeleportrWithdrawer is a simple contract capable of withdrawing funds from the\\n * TeleportrContract and sending them to some recipient address.\\n */\\ncontract TeleportrWithdrawer is AssetReceiver {\\n /**\\n * @notice Address of the Teleportr contract.\\n */\\n address public teleportr;\\n\\n /**\\n * @notice Address that will receive Teleportr withdrawals.\\n */\\n address public recipient;\\n\\n /**\\n * @notice Data to be sent to the recipient address.\\n */\\n bytes public data;\\n\\n /**\\n * @param _owner Initial owner of the contract.\\n */\\n constructor(address _owner) AssetReceiver(_owner) {}\\n\\n /**\\n * @notice Allows the owner to update the recipient address.\\n *\\n * @param _recipient New recipient address.\\n */\\n function setRecipient(address _recipient) external onlyOwner {\\n recipient = _recipient;\\n }\\n\\n /**\\n * @notice Allows the owner to update the Teleportr contract address.\\n *\\n * @param _teleportr New Teleportr contract address.\\n */\\n function setTeleportr(address _teleportr) external onlyOwner {\\n teleportr = _teleportr;\\n }\\n\\n /**\\n * @notice Allows the owner to update the data to be sent to the recipient address.\\n *\\n * @param _data New data to be sent to the recipient address.\\n */\\n function setData(bytes memory _data) external onlyOwner {\\n data = _data;\\n }\\n\\n /**\\n * @notice Withdraws the full balance of the Teleportr contract to the recipient address.\\n * Anyone is allowed to trigger this function since the recipient address cannot be\\n * controlled by the msg.sender.\\n */\\n function withdrawFromTeleportr() external {\\n Teleportr(teleportr).withdrawBalance();\\n (bool success, ) = recipient.call{ value: address(this).balance }(data);\\n require(success, \\\"TeleportrWithdrawer: send failed\\\");\\n }\\n}\\n\",\"keccak256\":\"0x26414ae14c7aee927c18075ee60757383e0202c2a2691f23b86c200c0ac24713\",\"license\":\"MIT\"},\"contracts/universal/Transactor.sol\":{\"content\":\"// SPDX-License-Identifier: MIT\\npragma solidity ^0.8.9;\\n\\nimport { Owned } from \\\"@rari-capital/solmate/src/auth/Owned.sol\\\";\\n\\n/**\\n * @title Transactor\\n * @notice Transactor is a minimal contract that can send transactions.\\n */\\ncontract Transactor is Owned {\\n /**\\n * @param _owner Initial contract owner.\\n */\\n constructor(address _owner) Owned(_owner) {}\\n\\n /**\\n * Sends a CALL to a target address.\\n *\\n * @param _target Address to call.\\n * @param _data Data to send with the call.\\n * @param _gas Amount of gas to send with the call.\\n * @param _value ETH value to send with the call.\\n * @return Boolean success value.\\n * @return Bytes data returned by the call.\\n */\\n function CALL(\\n address _target,\\n bytes memory _data,\\n uint256 _gas,\\n uint256 _value\\n ) external payable onlyOwner returns (bool, bytes memory) {\\n return _target.call{ gas: _gas, value: _value }(_data);\\n }\\n\\n /**\\n * Sends a DELEGATECALL to a target address.\\n *\\n * @param _target Address to call.\\n * @param _data Data to send with the call.\\n * @param _gas Amount of gas to send with the call.\\n * @return Boolean success value.\\n * @return Bytes data returned by the call.\\n */\\n function DELEGATECALL(\\n address _target,\\n bytes memory _data,\\n uint256 _gas\\n ) external payable onlyOwner returns (bool, bytes memory) {\\n // slither-disable-next-line controlled-delegatecall\\n return _target.delegatecall{ gas: _gas }(_data);\\n }\\n}\\n\",\"keccak256\":\"0xfe0d9c05a423d36775047e3285f76b874f8b887444d412a0d680c302c3b06a50\",\"license\":\"MIT\"}},\"version\":1}",
"bytecode": "0x608060405234801561001057600080fd5b506040516115ac3803806115ac83398101604081905261002f91610086565b600080546001600160a01b0319166001600160a01b03831690811782556040518392839283929091907f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d76908290a3505050506100b6565b60006020828403121561009857600080fd5b81516001600160a01b03811681146100af57600080fd5b9392505050565b6114e7806100c56000396000f3fe6080604052600436106100f75760003560e01c8063617d55421161008a5780638da5cb5b116100595780638da5cb5b146102f65780639456fbcc146103235780639e73dbea14610343578063ab62f0e11461035657600080fd5b8063617d55421461026757806366d003ac14610287578063690d8320146102b457806373d4a13a146102d457600080fd5b80634025feb2116100c65780634025feb2146101e657806344004cc1146102065780634782f779146102265780635cef8b4a1461024657600080fd5b806306fa29b21461013857806313af40351461018f5780633afe48c2146101b15780633bbed4a0146101c657600080fd5b366101335760405134815233907f4103257eaac983ca79a70d28f90dfc4fa16b619bb0c17ee7cab0d4034c2796249060200160405180910390a2005b600080fd5b34801561014457600080fd5b506001546101659073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561019b57600080fd5b506101af6101aa366004610ff1565b610376565b005b3480156101bd57600080fd5b506101af610452565b3480156101d257600080fd5b506101af6101e1366004610ff1565b61059a565b3480156101f257600080fd5b506101af610201366004611015565b610648565b34801561021257600080fd5b506101af610221366004611015565b6107c0565b34801561023257600080fd5b506101af610241366004611056565b610946565b61025961025436600461115c565b610a42565b60405161018692919061122f565b34801561027357600080fd5b506101af610282366004610ff1565b610b21565b34801561029357600080fd5b506002546101659073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c057600080fd5b506101af6102cf366004610ff1565b610bcf565b3480156102e057600080fd5b506102e9610c40565b6040516101869190611252565b34801561030257600080fd5b506000546101659073ffffffffffffffffffffffffffffffffffffffff1681565b34801561032f57600080fd5b506101af61033e366004611265565b610cce565b61025961035136600461129e565b610dde565b34801561036257600080fd5b506101af6103713660046112fe565b610ec1565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103e25760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635fd8c7106040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156104bc57600080fd5b505af11580156104d0573d6000803e3d6000fd5b50506002546040516000935073ffffffffffffffffffffffffffffffffffffffff9091169150479061050490600390611387565b60006040518083038185875af1925050503d8060008114610541576040519150601f19603f3d011682016040523d82523d6000602084013e610546565b606091505b50509050806105975760405162461bcd60e51b815260206004820181905260248201527f54656c65706f727472576974686472617765723a2073656e64206661696c656460448201526064016103d9565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106015760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106af5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152604482018390528416906323b872dd90606401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f30b478a5e196e55886228aa87ba74a7dfeba655e0a4d7ba275eabfc22aabb7a8846040516107b391815260200190565b60405180910390a4505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146108275760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526024820183905284169063a9059cbb90604401602060405180830381600087803b15801561089757600080fd5b505af11580156108ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cf919061145a565b508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f6b00f1c7883f053ba83e907fd1965b22fffe3c4111383e725f04638a566cdbfa846040516107b391815260200190565b60005473ffffffffffffffffffffffffffffffffffffffff1633146109ad5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b60405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f193505050501580156109f0573d6000803e3d6000fd5b5060405181815273ffffffffffffffffffffffffffffffffffffffff83169033907f1f12aa8b6d492dd9b98e2b00b0b20830c2a7ded65afac13b60d169a034ae90bc9060200160405180910390a35050565b6000805460609073ffffffffffffffffffffffffffffffffffffffff163314610aad5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b8473ffffffffffffffffffffffffffffffffffffffff168385604051610ad3919061147c565b6000604051808303818686f4925050503d8060008114610b0f576040519150601f19603f3d011682016040523d82523d6000602084013e610b14565b606091505b5091509150935093915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610b885760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c365760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b6105978147610946565b60038054610c4d90611333565b80601f0160208091040260200160405190810160405280929190818152602001828054610c7990611333565b8015610cc65780601f10610c9b57610100808354040283529160200191610cc6565b820191906000526020600020905b815481529060010190602001808311610ca957829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d355760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152610dda908390839073ffffffffffffffffffffffffffffffffffffffff8316906370a082319060240160206040518083038186803b158015610da257600080fd5b505afa158015610db6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102219190611498565b5050565b6000805460609073ffffffffffffffffffffffffffffffffffffffff163314610e495760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b8573ffffffffffffffffffffffffffffffffffffffff16848487604051610e70919061147c565b600060405180830381858888f193505050503d8060008114610eae576040519150601f19603f3d011682016040523d82523d6000602084013e610eb3565b606091505b509150915094509492505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f285760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b8051610dda906003906020840190828054610f4290611333565b90600052602060002090601f016020900481019282610f645760008555610faa565b82601f10610f7d57805160ff1916838001178555610faa565b82800160010185558215610faa579182015b82811115610faa578251825591602001919060010190610f8f565b50610fb6929150610fba565b5090565b5b80821115610fb65760008155600101610fbb565b73ffffffffffffffffffffffffffffffffffffffff8116811461059757600080fd5b60006020828403121561100357600080fd5b813561100e81610fcf565b9392505050565b60008060006060848603121561102a57600080fd5b833561103581610fcf565b9250602084013561104581610fcf565b929592945050506040919091013590565b6000806040838503121561106957600080fd5b823561107481610fcf565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126110c257600080fd5b813567ffffffffffffffff808211156110dd576110dd611082565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561112357611123611082565b8160405283815286602085880101111561113c57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060006060848603121561117157600080fd5b833561117c81610fcf565b9250602084013567ffffffffffffffff81111561119857600080fd5b6111a4868287016110b1565b925050604084013590509250925092565b60005b838110156111d05781810151838201526020016111b8565b838111156111df576000848401525b50505050565b600081518084526111fd8160208601602086016111b5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b821515815260406020820152600061124a60408301846111e5565b949350505050565b60208152600061100e60208301846111e5565b6000806040838503121561127857600080fd5b823561128381610fcf565b9150602083013561129381610fcf565b809150509250929050565b600080600080608085870312156112b457600080fd5b84356112bf81610fcf565b9350602085013567ffffffffffffffff8111156112db57600080fd5b6112e7878288016110b1565b949794965050505060408301359260600135919050565b60006020828403121561131057600080fd5b813567ffffffffffffffff81111561132757600080fd5b61124a848285016110b1565b600181811c9082168061134757607f821691505b60208210811415611381577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600080835481600182811c9150808316806113a357607f831692505b60208084108214156113dc577f4e487b710000000000000000000000000000000000000000000000000000000086526022600452602486fd5b8180156113f0576001811461141f5761144c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0086168952848901965061144c565b60008a81526020902060005b868110156114445781548b82015290850190830161142b565b505084890196505b509498975050505050505050565b60006020828403121561146c57600080fd5b8151801515811461100e57600080fd5b6000825161148e8184602087016111b5565b9190910192915050565b6000602082840312156114aa57600080fd5b505191905056fea26469706673582212203903a2f3f310c1942ac6f552df9012c64af2d384894531650c63a359397535f364736f6c63430008090033",
"deployedBytecode": "0x6080604052600436106100f75760003560e01c8063617d55421161008a5780638da5cb5b116100595780638da5cb5b146102f65780639456fbcc146103235780639e73dbea14610343578063ab62f0e11461035657600080fd5b8063617d55421461026757806366d003ac14610287578063690d8320146102b457806373d4a13a146102d457600080fd5b80634025feb2116100c65780634025feb2146101e657806344004cc1146102065780634782f779146102265780635cef8b4a1461024657600080fd5b806306fa29b21461013857806313af40351461018f5780633afe48c2146101b15780633bbed4a0146101c657600080fd5b366101335760405134815233907f4103257eaac983ca79a70d28f90dfc4fa16b619bb0c17ee7cab0d4034c2796249060200160405180910390a2005b600080fd5b34801561014457600080fd5b506001546101659073ffffffffffffffffffffffffffffffffffffffff1681565b60405173ffffffffffffffffffffffffffffffffffffffff90911681526020015b60405180910390f35b34801561019b57600080fd5b506101af6101aa366004610ff1565b610376565b005b3480156101bd57600080fd5b506101af610452565b3480156101d257600080fd5b506101af6101e1366004610ff1565b61059a565b3480156101f257600080fd5b506101af610201366004611015565b610648565b34801561021257600080fd5b506101af610221366004611015565b6107c0565b34801561023257600080fd5b506101af610241366004611056565b610946565b61025961025436600461115c565b610a42565b60405161018692919061122f565b34801561027357600080fd5b506101af610282366004610ff1565b610b21565b34801561029357600080fd5b506002546101659073ffffffffffffffffffffffffffffffffffffffff1681565b3480156102c057600080fd5b506101af6102cf366004610ff1565b610bcf565b3480156102e057600080fd5b506102e9610c40565b6040516101869190611252565b34801561030257600080fd5b506000546101659073ffffffffffffffffffffffffffffffffffffffff1681565b34801561032f57600080fd5b506101af61033e366004611265565b610cce565b61025961035136600461129e565b610dde565b34801561036257600080fd5b506101af6103713660046112fe565b610ec1565b60005473ffffffffffffffffffffffffffffffffffffffff1633146103e25760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064015b60405180910390fd5b600080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83169081178255604051909133917f8292fce18fa69edf4db7b94ea2e58241df0ae57f97e0a6c9b29067028bf92d769190a350565b600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16635fd8c7106040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156104bc57600080fd5b505af11580156104d0573d6000803e3d6000fd5b50506002546040516000935073ffffffffffffffffffffffffffffffffffffffff9091169150479061050490600390611387565b60006040518083038185875af1925050503d8060008114610541576040519150601f19603f3d011682016040523d82523d6000602084013e610546565b606091505b50509050806105975760405162461bcd60e51b815260206004820181905260248201527f54656c65706f727472576974686472617765723a2073656e64206661696c656460448201526064016103d9565b50565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106015760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff1633146106af5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b6040517f23b872dd00000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff8381166024830152604482018390528416906323b872dd90606401600060405180830381600087803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b505050508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f30b478a5e196e55886228aa87ba74a7dfeba655e0a4d7ba275eabfc22aabb7a8846040516107b391815260200190565b60405180910390a4505050565b60005473ffffffffffffffffffffffffffffffffffffffff1633146108275760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83811660048301526024820183905284169063a9059cbb90604401602060405180830381600087803b15801561089757600080fd5b505af11580156108ab573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906108cf919061145a565b508273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff167f6b00f1c7883f053ba83e907fd1965b22fffe3c4111383e725f04638a566cdbfa846040516107b391815260200190565b60005473ffffffffffffffffffffffffffffffffffffffff1633146109ad5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b60405173ffffffffffffffffffffffffffffffffffffffff83169082156108fc029083906000818181858888f193505050501580156109f0573d6000803e3d6000fd5b5060405181815273ffffffffffffffffffffffffffffffffffffffff83169033907f1f12aa8b6d492dd9b98e2b00b0b20830c2a7ded65afac13b60d169a034ae90bc9060200160405180910390a35050565b6000805460609073ffffffffffffffffffffffffffffffffffffffff163314610aad5760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b8473ffffffffffffffffffffffffffffffffffffffff168385604051610ad3919061147c565b6000604051808303818686f4925050503d8060008114610b0f576040519150601f19603f3d011682016040523d82523d6000602084013e610b14565b606091505b5091509150935093915050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610b885760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b60005473ffffffffffffffffffffffffffffffffffffffff163314610c365760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b6105978147610946565b60038054610c4d90611333565b80601f0160208091040260200160405190810160405280929190818152602001828054610c7990611333565b8015610cc65780601f10610c9b57610100808354040283529160200191610cc6565b820191906000526020600020905b815481529060010190602001808311610ca957829003601f168201915b505050505081565b60005473ffffffffffffffffffffffffffffffffffffffff163314610d355760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b6040517f70a08231000000000000000000000000000000000000000000000000000000008152306004820152610dda908390839073ffffffffffffffffffffffffffffffffffffffff8316906370a082319060240160206040518083038186803b158015610da257600080fd5b505afa158015610db6573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906102219190611498565b5050565b6000805460609073ffffffffffffffffffffffffffffffffffffffff163314610e495760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b8573ffffffffffffffffffffffffffffffffffffffff16848487604051610e70919061147c565b600060405180830381858888f193505050503d8060008114610eae576040519150601f19603f3d011682016040523d82523d6000602084013e610eb3565b606091505b509150915094509492505050565b60005473ffffffffffffffffffffffffffffffffffffffff163314610f285760405162461bcd60e51b815260206004820152600c60248201527f554e415554484f52495a4544000000000000000000000000000000000000000060448201526064016103d9565b8051610dda906003906020840190828054610f4290611333565b90600052602060002090601f016020900481019282610f645760008555610faa565b82601f10610f7d57805160ff1916838001178555610faa565b82800160010185558215610faa579182015b82811115610faa578251825591602001919060010190610f8f565b50610fb6929150610fba565b5090565b5b80821115610fb65760008155600101610fbb565b73ffffffffffffffffffffffffffffffffffffffff8116811461059757600080fd5b60006020828403121561100357600080fd5b813561100e81610fcf565b9392505050565b60008060006060848603121561102a57600080fd5b833561103581610fcf565b9250602084013561104581610fcf565b929592945050506040919091013590565b6000806040838503121561106957600080fd5b823561107481610fcf565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600082601f8301126110c257600080fd5b813567ffffffffffffffff808211156110dd576110dd611082565b604051601f83017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f0116810190828211818310171561112357611123611082565b8160405283815286602085880101111561113c57600080fd5b836020870160208301376000602085830101528094505050505092915050565b60008060006060848603121561117157600080fd5b833561117c81610fcf565b9250602084013567ffffffffffffffff81111561119857600080fd5b6111a4868287016110b1565b925050604084013590509250925092565b60005b838110156111d05781810151838201526020016111b8565b838111156111df576000848401525b50505050565b600081518084526111fd8160208601602086016111b5565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b821515815260406020820152600061124a60408301846111e5565b949350505050565b60208152600061100e60208301846111e5565b6000806040838503121561127857600080fd5b823561128381610fcf565b9150602083013561129381610fcf565b809150509250929050565b600080600080608085870312156112b457600080fd5b84356112bf81610fcf565b9350602085013567ffffffffffffffff8111156112db57600080fd5b6112e7878288016110b1565b949794965050505060408301359260600135919050565b60006020828403121561131057600080fd5b813567ffffffffffffffff81111561132757600080fd5b61124a848285016110b1565b600181811c9082168061134757607f821691505b60208210811415611381577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b600080835481600182811c9150808316806113a357607f831692505b60208084108214156113dc577f4e487b710000000000000000000000000000000000000000000000000000000086526022600452602486fd5b8180156113f0576001811461141f5761144c565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0086168952848901965061144c565b60008a81526020902060005b868110156114445781548b82015290850190830161142b565b505084890196505b509498975050505050505050565b60006020828403121561146c57600080fd5b8151801515811461100e57600080fd5b6000825161148e8184602087016111b5565b9190910192915050565b6000602082840312156114aa57600080fd5b505191905056fea26469706673582212203903a2f3f310c1942ac6f552df9012c64af2d384894531650c63a359397535f364736f6c63430008090033",
"devdoc": {
"kind": "dev",
"methods": {
"CALL(address,bytes,uint256,uint256)": {
"params": {
"_data": "Data to send with the call.",
"_gas": "Amount of gas to send with the call.",
"_target": "Address to call.",
"_value": "ETH value to send with the call."
},
"returns": {
"_0": "Boolean success value.",
"_1": "Bytes data returned by the call."
}
},
"DELEGATECALL(address,bytes,uint256)": {
"params": {
"_data": "Data to send with the call.",
"_gas": "Amount of gas to send with the call.",
"_target": "Address to call."
},
"returns": {
"_0": "Boolean success value.",
"_1": "Bytes data returned by the call."
}
},
"constructor": {
"params": {
"_owner": "Initial owner of the contract."
}
},
"setData(bytes)": {
"params": {
"_data": "New data to be sent to the recipient address."
}
},
"setRecipient(address)": {
"params": {
"_recipient": "New recipient address."
}
},
"setTeleportr(address)": {
"params": {
"_teleportr": "New Teleportr contract address."
}
},
"withdrawERC20(address,address)": {
"params": {
"_asset": "ERC20 token to withdraw.",
"_to": "Address to receive the ERC20 balance."
}
},
"withdrawERC20(address,address,uint256)": {
"params": {
"_amount": "Amount of ERC20 to withdraw.",
"_asset": "ERC20 token to withdraw.",
"_to": "Address to receive the ERC20 balance."
}
},
"withdrawERC721(address,address,uint256)": {
"params": {
"_asset": "ERC721 token to withdraw.",
"_id": "Token ID of the ERC721 token to withdraw.",
"_to": "Address to receive the ERC721 token."
}
},
"withdrawETH(address)": {
"params": {
"_to": "Address to receive the ETH balance."
}
},
"withdrawETH(address,uint256)": {
"params": {
"_amount": "Amount of ETH to withdraw.",
"_to": "Address to receive the ETH balance."
}
}
},
"title": "TeleportrWithdrawer",
"version": 1
},
"userdoc": {
"events": {
"ReceivedETH(address,uint256)": {
"notice": "Emitted when ETH is received by this address."
},
"WithdrewERC20(address,address,address,uint256)": {
"notice": "Emitted when ERC20 tokens are withdrawn from this address."
},
"WithdrewERC721(address,address,address,uint256)": {
"notice": "Emitted when ERC721 tokens are withdrawn from this address."
},
"WithdrewETH(address,address,uint256)": {
"notice": "Emitted when ETH is withdrawn from this address."
}
},
"kind": "user",
"methods": {
"CALL(address,bytes,uint256,uint256)": {
"notice": "Sends a CALL to a target address."
},
"DELEGATECALL(address,bytes,uint256)": {
"notice": "Sends a DELEGATECALL to a target address."
},
"data()": {
"notice": "Data to be sent to the recipient address."
},
"recipient()": {
"notice": "Address that will receive Teleportr withdrawals."
},
"setData(bytes)": {
"notice": "Allows the owner to update the data to be sent to the recipient address."
},
"setRecipient(address)": {
"notice": "Allows the owner to update the recipient address."
},
"setTeleportr(address)": {
"notice": "Allows the owner to update the Teleportr contract address."
},
"teleportr()": {
"notice": "Address of the Teleportr contract."
},
"withdrawERC20(address,address)": {
"notice": "Withdraws full ERC20 balance to the recipient."
},
"withdrawERC20(address,address,uint256)": {
"notice": "Withdraws partial ERC20 balance to the recipient."
},
"withdrawERC721(address,address,uint256)": {
"notice": "Withdraws ERC721 token to the recipient."
},
"withdrawETH(address)": {
"notice": "Withdraws full ETH balance to the recipient."
},
"withdrawETH(address,uint256)": {
"notice": "Withdraws partial ETH balance to the recipient."
},
"withdrawFromTeleportr()": {
"notice": "Withdraws the full balance of the Teleportr contract to the recipient address. Anyone is allowed to trigger this function since the recipient address cannot be controlled by the msg.sender."
}
},
"notice": "The TeleportrWithdrawer is a simple contract capable of withdrawing funds from the TeleportrContract and sending them to some recipient address.",
"version": 1
},
"storageLayout": {
"storage": [
{
"astId": 4371,
"contract": "contracts/universal/TeleportrWithdrawer.sol:TeleportrWithdrawer",
"label": "owner",
"offset": 0,
"slot": "0",
"type": "t_address"
},
{
"astId": 6314,
"contract": "contracts/universal/TeleportrWithdrawer.sol:TeleportrWithdrawer",
"label": "teleportr",
"offset": 0,
"slot": "1",
"type": "t_address"
},
{
"astId": 6317,
"contract": "contracts/universal/TeleportrWithdrawer.sol:TeleportrWithdrawer",
"label": "recipient",
"offset": 0,
"slot": "2",
"type": "t_address"
},
{
"astId": 6320,
"contract": "contracts/universal/TeleportrWithdrawer.sol:TeleportrWithdrawer",
"label": "data",
"offset": 0,
"slot": "3",
"type": "t_bytes_storage"
}
],
"types": {
"t_address": {
"encoding": "inplace",
"label": "address",
"numberOfBytes": "20"
},
"t_bytes_storage": {
"encoding": "bytes",
"label": "bytes",
"numberOfBytes": "32"
}
}
}
}
\ No newline at end of file
{
"language": "Solidity",
"sources": {
"contracts/testing/helpers/TestERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\n\ncontract TestERC20 is ERC20 {\n constructor() ERC20(\"TEST\", \"TST\", 18) {}\n\n function mint(address to, uint256 value) public {\n _mint(to, value);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n uint8 public immutable decimals;\n\n /*//////////////////////////////////////////////////////////////\n ERC20 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 public totalSupply;\n\n mapping(address => uint256) public balanceOf;\n\n mapping(address => mapping(address => uint256)) public allowance;\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal immutable INITIAL_CHAIN_ID;\n\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n mapping(address => uint256) public nonces;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals\n ) {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n INITIAL_CHAIN_ID = block.chainid;\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 amount) public virtual returns (bool) {\n allowance[msg.sender][spender] = amount;\n\n emit Approval(msg.sender, spender, amount);\n\n return true;\n }\n\n function transfer(address to, uint256 amount) public virtual returns (bool) {\n balanceOf[msg.sender] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(msg.sender, to, amount);\n\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual returns (bool) {\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n balanceOf[from] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual {\n require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n // Unchecked because the only math done is incrementing\n // the owner's nonce which cannot realistically overflow.\n unchecked {\n address recoveredAddress = ecrecover(\n keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(\n abi.encode(\n keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n ),\n owner,\n spender,\n value,\n nonces[owner]++,\n deadline\n )\n )\n )\n ),\n v,\n r,\n s\n );\n\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n allowance[recoveredAddress][spender] = value;\n }\n\n emit Approval(owner, spender, value);\n }\n\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n }\n\n function computeDomainSeparator() internal view virtual returns (bytes32) {\n return\n keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(name)),\n keccak256(\"1\"),\n block.chainid,\n address(this)\n )\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 amount) internal virtual {\n totalSupply += amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal virtual {\n balanceOf[from] -= amount;\n\n // Cannot underflow because a user's balance\n // will never be larger than the total supply.\n unchecked {\n totalSupply -= amount;\n }\n\n emit Transfer(from, address(0), amount);\n }\n}\n"
},
"contracts/universal/AssetReceiver.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\nimport { Transactor } from \"./Transactor.sol\";\n\n/**\n * @title AssetReceiver\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\n */\ncontract AssetReceiver is Transactor {\n /**\n * @notice Emitted when ETH is received by this address.\n *\n * @param from Address that sent ETH to this contract.\n * @param amount Amount of ETH received.\n */\n event ReceivedETH(address indexed from, uint256 amount);\n\n /**\n * @notice Emitted when ETH is withdrawn from this address.\n *\n * @param withdrawer Address that triggered the withdrawal.\n * @param recipient Address that received the withdrawal.\n * @param amount ETH amount withdrawn.\n */\n event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\n\n /**\n * @notice Emitted when ERC20 tokens are withdrawn from this address.\n *\n * @param withdrawer Address that triggered the withdrawal.\n * @param recipient Address that received the withdrawal.\n * @param asset Address of the token being withdrawn.\n * @param amount ERC20 amount withdrawn.\n */\n event WithdrewERC20(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 amount\n );\n\n /**\n * @notice Emitted when ERC20 tokens are withdrawn from this address.\n *\n * @param withdrawer Address that triggered the withdrawal.\n * @param recipient Address that received the withdrawal.\n * @param asset Address of the token being withdrawn.\n * @param id Token ID being withdrawn.\n */\n event WithdrewERC721(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 id\n );\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Transactor(_owner) {}\n\n /**\n * @notice Make sure we can receive ETH.\n */\n receive() external payable {\n emit ReceivedETH(msg.sender, msg.value);\n }\n\n /**\n * @notice Withdraws full ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n */\n function withdrawETH(address payable _to) external onlyOwner {\n withdrawETH(_to, address(this).balance);\n }\n\n /**\n * @notice Withdraws partial ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n * @param _amount Amount of ETH to withdraw.\n */\n function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\n // slither-disable-next-line reentrancy-unlimited-gas\n (bool success, ) = _to.call{ value: _amount }(\"\");\n emit WithdrewETH(msg.sender, _to, _amount);\n }\n\n /**\n * @notice Withdraws full ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n */\n function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\n withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\n }\n\n /**\n * @notice Withdraws partial ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n * @param _amount Amount of ERC20 to withdraw.\n */\n function withdrawERC20(\n ERC20 _asset,\n address _to,\n uint256 _amount\n ) public onlyOwner {\n // slither-disable-next-line unchecked-transfer\n _asset.transfer(_to, _amount);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\n }\n\n /**\n * @notice Withdraws ERC721 token to the recipient.\n *\n * @param _asset ERC721 token to withdraw.\n * @param _to Address to receive the ERC721 token.\n * @param _id Token ID of the ERC721 token to withdraw.\n */\n function withdrawERC721(\n ERC721 _asset,\n address _to,\n uint256 _id\n ) external onlyOwner {\n _asset.transferFrom(address(this), _to, _id);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) internal _ownerOf;\n\n mapping(address => uint256) internal _balanceOf;\n\n function ownerOf(uint256 id) public view virtual returns (address owner) {\n require((owner = _ownerOf[id]) != address(0), \"NOT_MINTED\");\n }\n\n function balanceOf(address owner) public view virtual returns (uint256) {\n require(owner != address(0), \"ZERO_ADDRESS\");\n\n return _balanceOf[owner];\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) public getApproved;\n\n mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 id) public virtual {\n address owner = _ownerOf[id];\n\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n getApproved[id] = spender;\n\n emit Approval(owner, spender, id);\n }\n\n function setApprovalForAll(address operator, bool approved) public virtual {\n isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n require(from == _ownerOf[id], \"WRONG_FROM\");\n\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(\n msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\n \"NOT_AUTHORIZED\"\n );\n\n // Underflow of the sender's balance is impossible because we check for\n // ownership above and the recipient's balance can't realistically overflow.\n unchecked {\n _balanceOf[from]--;\n\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n delete getApproved[id];\n\n emit Transfer(from, to, id);\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n bytes calldata data\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 id) internal virtual {\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(_ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n // Counter overflow is incredibly unrealistic.\n unchecked {\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n emit Transfer(address(0), to, id);\n }\n\n function _burn(uint256 id) internal virtual {\n address owner = _ownerOf[id];\n\n require(owner != address(0), \"NOT_MINTED\");\n\n // Ownership check above ensures no underflow.\n unchecked {\n _balanceOf[owner]--;\n }\n\n delete _ownerOf[id];\n\n delete getApproved[id];\n\n emit Transfer(owner, address(0), id);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL SAFE MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _safeMint(address to, uint256 id) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _safeMint(\n address to,\n uint256 id,\n bytes memory data\n ) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721TokenReceiver {\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external virtual returns (bytes4) {\n return ERC721TokenReceiver.onERC721Received.selector;\n }\n}\n"
},
"contracts/universal/Transactor.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { Owned } from \"@rari-capital/solmate/src/auth/Owned.sol\";\n\n/**\n * @title Transactor\n * @notice Transactor is a minimal contract that can send transactions.\n */\ncontract Transactor is Owned {\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Owned(_owner) {}\n\n /**\n * Sends a CALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _value ETH value to send with the call.\n *\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function CALL(\n address _target,\n bytes memory _data,\n uint256 _value\n ) external payable onlyOwner returns (bool, bytes memory) {\n return _target.call{ value: _value }(_data);\n }\n\n /**\n * Sends a DELEGATECALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n *\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function DELEGATECALL(address _target, bytes memory _data)\n external\n payable\n onlyOwner\n returns (bool, bytes memory)\n {\n // slither-disable-next-line controlled-delegatecall\n return _target.delegatecall(_data);\n }\n}\n"
},
"@rari-capital/solmate/src/auth/Owned.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event OwnerUpdated(address indexed user, address indexed newOwner);\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP STORAGE\n //////////////////////////////////////////////////////////////*/\n\n address public owner;\n\n modifier onlyOwner() virtual {\n require(msg.sender == owner, \"UNAUTHORIZED\");\n\n _;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address _owner) {\n owner = _owner;\n\n emit OwnerUpdated(address(0), _owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function setOwner(address newOwner) public virtual onlyOwner {\n owner = newOwner;\n\n emit OwnerUpdated(msg.sender, newOwner);\n }\n}\n"
},
"contracts/universal/drippie/Drippie.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { AssetReceiver } from \"../AssetReceiver.sol\";\nimport { IDripCheck } from \"./IDripCheck.sol\";\n\n/**\n * @title Drippie\n * @notice Drippie is a system for managing automated contract interactions. A specific interaction\n * is called a \"drip\" and can be executed according to some condition (called a dripcheck)\n * and an execution interval. Drips cannot be executed faster than the execution interval.\n * Drips can trigger arbitrary contract calls where the calling contract is this contract\n * address. Drips can also send ETH value, which makes them ideal for keeping addresses\n * sufficiently funded with ETH. Drippie is designed to be connected with smart contract\n * automation services so that drips can be executed automatically. However, Drippie is\n * specifically designed to be separated from these services so that trust assumptions are\n * better compartmentalized.\n */\ncontract Drippie is AssetReceiver {\n /**\n * @notice Enum representing different status options for a given drip.\n *\n * @custom:value NONE Drip does not exist.\n * @custom:value PAUSED Drip is paused and cannot be executed until reactivated.\n * @custom:value ACTIVE Drip is active and can be executed.\n * @custom:value ARCHIVED Drip is archived and can no longer be executed or reactivated.\n */\n enum DripStatus {\n NONE,\n PAUSED,\n ACTIVE,\n ARCHIVED\n }\n\n /**\n * @notice Represents a drip action.\n */\n struct DripAction {\n address payable target;\n bytes data;\n uint256 value;\n }\n\n /**\n * @notice Represents the configuration for a given drip.\n */\n struct DripConfig {\n bool reentrant;\n uint256 interval;\n IDripCheck dripcheck;\n bytes checkparams;\n DripAction[] actions;\n }\n\n /**\n * @notice Represents the state of an active drip.\n */\n struct DripState {\n DripStatus status;\n DripConfig config;\n uint256 last;\n uint256 count;\n }\n\n /**\n * @notice Emitted when a new drip is created.\n *\n * @param nameref Indexed name parameter (hashed).\n * @param name Unindexed name parameter (unhashed).\n * @param config Config for the created drip.\n */\n event DripCreated(\n // Emit name twice because indexed version is hashed.\n string indexed nameref,\n string name,\n DripConfig config\n );\n\n /**\n * @notice Emitted when a drip status is updated.\n *\n * @param nameref Indexed name parameter (hashed).\n * @param name Unindexed name parameter (unhashed).\n * @param status New drip status.\n */\n event DripStatusUpdated(\n // Emit name twice because indexed version is hashed.\n string indexed nameref,\n string name,\n DripStatus status\n );\n\n /**\n * @notice Emitted when a drip is executed.\n *\n * @param nameref Indexed name parameter (hashed).\n * @param name Unindexed name parameter (unhashed).\n * @param executor Address that executed the drip.\n * @param timestamp Time when the drip was executed.\n */\n event DripExecuted(\n // Emit name twice because indexed version is hashed.\n string indexed nameref,\n string name,\n address executor,\n uint256 timestamp\n );\n\n /**\n * @notice Maps from drip names to drip states.\n */\n mapping(string => DripState) public drips;\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) AssetReceiver(_owner) {}\n\n /**\n * @notice Creates a new drip with the given name and configuration. Once created, drips cannot\n * be modified in any way (this is a security measure). If you want to update a drip,\n * simply pause (and potentially archive) the existing drip and create a new one.\n *\n * @param _name Name of the drip.\n * @param _config Configuration for the drip.\n */\n function create(string calldata _name, DripConfig calldata _config) external onlyOwner {\n // Make sure this drip doesn't already exist. We *must* guarantee that no other function\n // will ever set the status of a drip back to NONE after it's been created. This is why\n // archival is a separate status.\n require(\n drips[_name].status == DripStatus.NONE,\n \"Drippie: drip with that name already exists\"\n );\n\n // Validate the drip interval, only allowing an interval of zero if the drip has explicitly\n // been marked as reentrant. Prevents client-side bugs making a drip infinitely executable\n // within the same block (of course, restricted by gas limits).\n if (_config.reentrant) {\n require(\n _config.interval == 0,\n \"Drippie: if allowing reentrant drip, must set interval to zero\"\n );\n } else {\n require(\n _config.interval > 0,\n \"Drippie: interval must be greater than zero if drip is not reentrant\"\n );\n }\n\n // We initialize this way because Solidity won't let us copy arrays into storage yet.\n DripState storage state = drips[_name];\n state.status = DripStatus.PAUSED;\n state.config.reentrant = _config.reentrant;\n state.config.interval = _config.interval;\n state.config.dripcheck = _config.dripcheck;\n state.config.checkparams = _config.checkparams;\n\n // Solidity doesn't let us copy arrays into storage, so we push each array one by one.\n for (uint256 i = 0; i < _config.actions.length; i++) {\n state.config.actions.push(_config.actions[i]);\n }\n\n // Tell the world!\n emit DripCreated(_name, _name, _config);\n }\n\n /**\n * @notice Sets the status for a given drip. The behavior of this function depends on the\n * status that the user is trying to set. A drip can always move between ACTIVE and\n * PAUSED, but it can never move back to NONE and once ARCHIVED, it can never move back\n * to ACTIVE or PAUSED.\n *\n * @param _name Name of the drip to update.\n * @param _status New drip status.\n */\n function status(string calldata _name, DripStatus _status) external onlyOwner {\n // Make sure we can never set drip status back to NONE. A simple security measure to\n // prevent accidental overwrites if this code is ever updated down the line.\n require(\n _status != DripStatus.NONE,\n \"Drippie: drip status can never be set back to NONE after creation\"\n );\n\n // Load the drip status once to avoid unnecessary SLOADs.\n DripStatus curr = drips[_name].status;\n\n // Make sure the drip in question actually exists. Not strictly necessary but there doesn't\n // seem to be any clear reason why you would want to do this, and it may save some gas in\n // the case of a front-end bug.\n require(\n curr != DripStatus.NONE,\n \"Drippie: drip with that name does not exist and cannot be updated\"\n );\n\n // Once a drip has been archived, it cannot be un-archived. This is, after all, the entire\n // point of archiving a drip.\n require(\n curr != DripStatus.ARCHIVED,\n \"Drippie: drip with that name has been archived and cannot be updated\"\n );\n\n // Although not strictly necessary, we make sure that the status here is actually changing.\n // This may save the client some gas if there's a front-end bug and the user accidentally\n // tries to \"change\" the status to the same value as before.\n require(\n curr != _status,\n \"Drippie: cannot set drip status to the same status as its current status\"\n );\n\n // If the user is trying to archive this drip, make sure the drip has been paused. We do\n // not allow users to archive active drips so that the effects of this action are more\n // abundantly clear.\n if (_status == DripStatus.ARCHIVED) {\n require(\n curr == DripStatus.PAUSED,\n \"Drippie: drip must first be paused before being archived\"\n );\n }\n\n // If we made it here then we can safely update the status.\n drips[_name].status = _status;\n emit DripStatusUpdated(_name, _name, _status);\n }\n\n /**\n * @notice Checks if a given drip is executable.\n *\n * @param _name Drip to check.\n *\n * @return True if the drip is executable, reverts otherwise.\n */\n function executable(string calldata _name) public view returns (bool) {\n DripState storage state = drips[_name];\n\n // Only allow active drips to be executed, an obvious security measure.\n require(\n state.status == DripStatus.ACTIVE,\n \"Drippie: selected drip does not exist or is not currently active\"\n );\n\n // Don't drip if the drip interval has not yet elapsed since the last time we dripped. This\n // is a safety measure that prevents a malicious recipient from, e.g., spending all of\n // their funds and repeatedly requesting new drips. Limits the potential impact of a\n // compromised recipient to just a single drip interval, after which the drip can be paused\n // by the owner address.\n require(\n state.last + state.config.interval <= block.timestamp,\n \"Drippie: drip interval has not elapsed since last drip\"\n );\n\n // Make sure we're allowed to execute this drip.\n require(\n state.config.dripcheck.check(state.config.checkparams),\n \"Drippie: dripcheck failed so drip is not yet ready to be triggered\"\n );\n\n // Alright, we're good to execute.\n return true;\n }\n\n /**\n * @notice Triggers a drip. This function is deliberately left as a public function because the\n * assumption being made here is that setting the drip to ACTIVE is an affirmative\n * signal that the drip should be executable according to the drip parameters, drip\n * check, and drip interval. Note that drip parameters are read entirely from the state\n * and are not supplied as user input, so there should not be any way for a\n * non-authorized user to influence the behavior of the drip. Note that the drip check\n * is executed only **once** at the beginning of the call to the drip function and will\n * not be executed again between the drip actions within this call.\n *\n * @param _name Name of the drip to trigger.\n */\n function drip(string calldata _name) external {\n DripState storage state = drips[_name];\n\n // Make sure the drip can be executed. Since executable reverts if the drip is not ready to\n // be executed, we don't need to do an assertion that the returned value is true.\n executable(_name);\n\n // Update the last execution time for this drip before the call. Note that it's entirely\n // possible for a drip to be executed multiple times per block or even multiple times\n // within the same transaction (via re-entrancy) if the drip interval is set to zero. Users\n // should set a drip interval of 1 if they'd like the drip to be executed only once per\n // block (since this will then prevent re-entrancy).\n state.last = block.timestamp;\n\n // Update the number of times this drip has been executed. Although this increases the cost\n // of using Drippie, it slightly simplifies the client-side by not having to worry about\n // counting drips via events. Useful for monitoring the rate of drip execution.\n state.count++;\n\n // Execute each action in the drip. We allow drips to have multiple actions because there\n // are scenarios in which a contract must do multiple things atomically. For example, the\n // contract may need to withdraw ETH from one account and then deposit that ETH into\n // another account within the same transaction.\n uint256 len = state.config.actions.length;\n for (uint256 i = 0; i < len; i++) {\n // Must be marked as \"storage\" because copying structs into memory is not yet supported\n // by Solidity. Won't significantly reduce gas costs but at least makes it easier to\n // read what the rest of this section is doing.\n DripAction storage action = state.config.actions[i];\n\n // Actually execute the action. We could use ExcessivelySafeCall here but not strictly\n // necessary (worst case, a drip gets bricked IFF the target is malicious, doubt this\n // will ever happen in practice). Could save a marginal amount of gas to ignore the\n // returndata.\n // slither-disable-next-line calls-loop\n (bool success, ) = action.target.call{ value: action.value }(action.data);\n\n // Generally should not happen, but could if there's a misconfiguration (e.g., passing\n // the wrong data to the target contract), the recipient is not payable, or\n // insufficient gas was supplied to this transaction. We revert so the drip can be\n // fixed and triggered again later. Means we cannot emit an event to alert of the\n // failure, but can reasonably be detected by off-chain services even without an event.\n // Note that this forces the drip executor to supply sufficient gas to the call\n // (assuming there is some sufficient gas limit that exists, otherwise the drip will\n // not execute).\n require(\n success,\n \"Drippie: drip was unsuccessful, please check your configuration for mistakes\"\n );\n }\n\n emit DripExecuted(_name, _name, msg.sender, block.timestamp);\n }\n}\n"
},
"contracts/universal/drippie/IDripCheck.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\ninterface IDripCheck {\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\n // possible to easily encode parameters on the client side. Solidity does not support generics\n // so it's not possible to do this with explicit typing.\n\n /**\n * @notice Checks whether a drip should be executable.\n *\n * @param _params Encoded parameters for the drip check.\n *\n * @return Whether the drip should be executed.\n */\n function check(bytes memory _params) external view returns (bool);\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckTrue.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckTrue\n * @notice DripCheck that always returns true.\n */\ncontract CheckTrue is IDripCheck {\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory) external pure returns (bool) {\n return true;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\ninterface IGelatoTreasury {\n function userTokenBalance(address _user, address _token) external view returns (uint256);\n}\n\n/**\n * @title CheckGelatoLow\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\n */\ncontract CheckGelatoLow is IDripCheck {\n struct Params {\n address treasury;\n uint256 threshold;\n address recipient;\n }\n\n /**\n * @notice External event used to help client-side tooling encode parameters.\n *\n * @param params Parameters to encode.\n */\n event _EventToExposeStructInABI__Params(Params params);\n\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check GelatoTreasury ETH balance is below threshold.\n return\n IGelatoTreasury(params.treasury).userTokenBalance(\n params.recipient,\n // Gelato represents ETH as 0xeeeee....eeeee\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\n ) < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceLow\n * @notice DripCheck for checking if an account's balance is below a given threshold.\n */\ncontract CheckBalanceLow is IDripCheck {\n struct Params {\n address target;\n uint256 threshold;\n }\n\n /**\n * @notice External event used to help client-side tooling encode parameters.\n *\n * @param params Parameters to encode.\n */\n event _EventToExposeStructInABI__Params(Params params);\n\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target ETH balance is below threshold.\n return params.target.balance < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.16;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceHigh\n * @notice DripCheck for checking if an account's balance is above a given threshold.\n */\ncontract CheckBalanceHigh is IDripCheck {\n struct Params {\n address target;\n uint256 threshold;\n }\n\n /**\n * @notice External event used to help client-side tooling encode parameters.\n *\n * @param params Parameters to encode.\n */\n event _EventToExposeStructInABI__Params(Params params);\n\n /**\n * @inheritdoc IDripCheck\n */\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target balance is above threshold.\n return params.target.balance > params.threshold;\n }\n}\n"
},
"contracts/testing/helpers/TestERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.0;\n\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\n\ncontract TestERC721 is ERC721 {\n constructor() ERC721(\"TEST\", \"TST\") {}\n\n function mint(address to, uint256 tokenId) public {\n _mint(to, tokenId);\n }\n\n function tokenURI(uint256) public pure virtual override returns (string memory) {}\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
\ No newline at end of file
{
"language": "Solidity",
"sources": {
"contracts/universal/AssetReceiver.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\nimport { Transactor } from \"./Transactor.sol\";\n\n/**\n * @title AssetReceiver\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\n */\ncontract AssetReceiver is Transactor {\n /**\n * Emitted when ETH is received by this address.\n */\n event ReceivedETH(address indexed from, uint256 amount);\n\n /**\n * Emitted when ETH is withdrawn from this address.\n */\n event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\n\n /**\n * Emitted when ERC20 tokens are withdrawn from this address.\n */\n event WithdrewERC20(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 amount\n );\n\n /**\n * Emitted when ERC721 tokens are withdrawn from this address.\n */\n event WithdrewERC721(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 id\n );\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Transactor(_owner) {}\n\n /**\n * Make sure we can receive ETH.\n */\n receive() external payable {\n emit ReceivedETH(msg.sender, msg.value);\n }\n\n /**\n * Withdraws full ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n */\n function withdrawETH(address payable _to) external onlyOwner {\n withdrawETH(_to, address(this).balance);\n }\n\n /**\n * Withdraws partial ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n * @param _amount Amount of ETH to withdraw.\n */\n function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\n // slither-disable-next-line reentrancy-unlimited-gas\n _to.transfer(_amount);\n emit WithdrewETH(msg.sender, _to, _amount);\n }\n\n /**\n * Withdraws full ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n */\n function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\n withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\n }\n\n /**\n * Withdraws partial ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n * @param _amount Amount of ERC20 to withdraw.\n */\n function withdrawERC20(\n ERC20 _asset,\n address _to,\n uint256 _amount\n ) public onlyOwner {\n // slither-disable-next-line unchecked-transfer\n _asset.transfer(_to, _amount);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\n }\n\n /**\n * Withdraws ERC721 token to the recipient.\n *\n * @param _asset ERC721 token to withdraw.\n * @param _to Address to receive the ERC721 token.\n * @param _id Token ID of the ERC721 token to withdraw.\n */\n function withdrawERC721(\n ERC721 _asset,\n address _to,\n uint256 _id\n ) external onlyOwner {\n _asset.transferFrom(address(this), _to, _id);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n uint8 public immutable decimals;\n\n /*//////////////////////////////////////////////////////////////\n ERC20 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 public totalSupply;\n\n mapping(address => uint256) public balanceOf;\n\n mapping(address => mapping(address => uint256)) public allowance;\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal immutable INITIAL_CHAIN_ID;\n\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n mapping(address => uint256) public nonces;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals\n ) {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n INITIAL_CHAIN_ID = block.chainid;\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 amount) public virtual returns (bool) {\n allowance[msg.sender][spender] = amount;\n\n emit Approval(msg.sender, spender, amount);\n\n return true;\n }\n\n function transfer(address to, uint256 amount) public virtual returns (bool) {\n balanceOf[msg.sender] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(msg.sender, to, amount);\n\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual returns (bool) {\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n balanceOf[from] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual {\n require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n // Unchecked because the only math done is incrementing\n // the owner's nonce which cannot realistically overflow.\n unchecked {\n address recoveredAddress = ecrecover(\n keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(\n abi.encode(\n keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n ),\n owner,\n spender,\n value,\n nonces[owner]++,\n deadline\n )\n )\n )\n ),\n v,\n r,\n s\n );\n\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n allowance[recoveredAddress][spender] = value;\n }\n\n emit Approval(owner, spender, value);\n }\n\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n }\n\n function computeDomainSeparator() internal view virtual returns (bytes32) {\n return\n keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(name)),\n keccak256(\"1\"),\n block.chainid,\n address(this)\n )\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 amount) internal virtual {\n totalSupply += amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal virtual {\n balanceOf[from] -= amount;\n\n // Cannot underflow because a user's balance\n // will never be larger than the total supply.\n unchecked {\n totalSupply -= amount;\n }\n\n emit Transfer(from, address(0), amount);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) internal _ownerOf;\n\n mapping(address => uint256) internal _balanceOf;\n\n function ownerOf(uint256 id) public view virtual returns (address owner) {\n require((owner = _ownerOf[id]) != address(0), \"NOT_MINTED\");\n }\n\n function balanceOf(address owner) public view virtual returns (uint256) {\n require(owner != address(0), \"ZERO_ADDRESS\");\n\n return _balanceOf[owner];\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) public getApproved;\n\n mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 id) public virtual {\n address owner = _ownerOf[id];\n\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n getApproved[id] = spender;\n\n emit Approval(owner, spender, id);\n }\n\n function setApprovalForAll(address operator, bool approved) public virtual {\n isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n require(from == _ownerOf[id], \"WRONG_FROM\");\n\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(\n msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\n \"NOT_AUTHORIZED\"\n );\n\n // Underflow of the sender's balance is impossible because we check for\n // ownership above and the recipient's balance can't realistically overflow.\n unchecked {\n _balanceOf[from]--;\n\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n delete getApproved[id];\n\n emit Transfer(from, to, id);\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n bytes calldata data\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 id) internal virtual {\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(_ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n // Counter overflow is incredibly unrealistic.\n unchecked {\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n emit Transfer(address(0), to, id);\n }\n\n function _burn(uint256 id) internal virtual {\n address owner = _ownerOf[id];\n\n require(owner != address(0), \"NOT_MINTED\");\n\n // Ownership check above ensures no underflow.\n unchecked {\n _balanceOf[owner]--;\n }\n\n delete _ownerOf[id];\n\n delete getApproved[id];\n\n emit Transfer(owner, address(0), id);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL SAFE MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _safeMint(address to, uint256 id) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _safeMint(\n address to,\n uint256 id,\n bytes memory data\n ) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721TokenReceiver {\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external virtual returns (bytes4) {\n return ERC721TokenReceiver.onERC721Received.selector;\n }\n}\n"
},
"contracts/universal/Transactor.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { Owned } from \"@rari-capital/solmate/src/auth/Owned.sol\";\n\n/**\n * @title Transactor\n * @notice Transactor is a minimal contract that can send transactions.\n */\ncontract Transactor is Owned {\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Owned(_owner) {}\n\n /**\n * Sends a CALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @param _value ETH value to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function CALL(\n address _target,\n bytes memory _data,\n uint256 _gas,\n uint256 _value\n ) external payable onlyOwner returns (bool, bytes memory) {\n return _target.call{ gas: _gas, value: _value }(_data);\n }\n\n /**\n * Sends a DELEGATECALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function DELEGATECALL(\n address _target,\n bytes memory _data,\n uint256 _gas\n ) external payable onlyOwner returns (bool, bytes memory) {\n // slither-disable-next-line controlled-delegatecall\n return _target.delegatecall{ gas: _gas }(_data);\n }\n}\n"
},
"@rari-capital/solmate/src/auth/Owned.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event OwnerUpdated(address indexed user, address indexed newOwner);\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP STORAGE\n //////////////////////////////////////////////////////////////*/\n\n address public owner;\n\n modifier onlyOwner() virtual {\n require(msg.sender == owner, \"UNAUTHORIZED\");\n\n _;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address _owner) {\n owner = _owner;\n\n emit OwnerUpdated(address(0), _owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function setOwner(address newOwner) public virtual onlyOwner {\n owner = newOwner;\n\n emit OwnerUpdated(msg.sender, newOwner);\n }\n}\n"
},
"contracts/universal/drippie/Drippie.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { AssetReceiver } from \"../AssetReceiver.sol\";\nimport { IDripCheck } from \"./IDripCheck.sol\";\n\n/**\n * @title Drippie\n * @notice Drippie is a system for managing automated contract interactions. A specific interaction\n * is called a \"drip\" and can be executed according to some condition (called a dripcheck) and an\n * execution interval. Drips cannot be executed faster than the execution interval. Drips can\n * trigger arbitrary contract calls where the calling contract is this contract address. Drips can\n * also send ETH value, which makes them ideal for keeping addresses sufficiently funded with ETH.\n * Drippie is designed to be connected with smart contract automation services so that drips can be\n * executed automatically. However, Drippie is specifically designed to be separated from these\n * services so that trust assumptions are better compartmentalized.\n */\ncontract Drippie is AssetReceiver {\n /**\n * Enum representing different status options for a given drip.\n */\n enum DripStatus {\n NONE,\n ACTIVE,\n PAUSED,\n ARCHIVED\n }\n\n /**\n * Represents a drip action.\n */\n struct DripAction {\n address payable target;\n bytes data;\n uint256 value;\n }\n\n /**\n * Represents the configuration for a given drip.\n */\n struct DripConfig {\n uint256 interval;\n IDripCheck dripcheck;\n bytes checkparams;\n DripAction[] actions;\n }\n\n /**\n * Represents the state of an active drip.\n */\n struct DripState {\n DripStatus status;\n DripConfig config;\n uint256 last;\n }\n\n /**\n * Emitted when a new drip is created.\n */\n event DripCreated(string indexed name, DripConfig config);\n\n /**\n * Emitted when a drip status is updated.\n */\n event DripStatusUpdated(string indexed name, DripStatus status);\n\n /**\n * Emitted when a drip is executed.\n */\n event DripExecuted(string indexed name, address indexed executor, uint256 timestamp);\n\n /**\n * Maps from drip names to drip states.\n */\n mapping(string => DripState) public drips;\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) AssetReceiver(_owner) {}\n\n /**\n * Creates a new drip with the given name and configuration. Once created, drips cannot be\n * modified in any way (this is a security measure). If you want to update a drip, simply pause\n * (and potentially archive) the existing drip and create a new one.\n *\n * @param _name Name of the drip.\n * @param _config Configuration for the drip.\n */\n function create(string memory _name, DripConfig memory _config) external onlyOwner {\n // Make sure this drip doesn't already exist. We *must* guarantee that no other function\n // will ever set the status of a drip back to NONE after it's been created. This is why\n // archival is a separate status.\n require(\n drips[_name].status == DripStatus.NONE,\n \"Drippie: drip with that name already exists\"\n );\n\n // We initialize this way because Solidity won't let us copy arrays into storage yet.\n DripState storage state = drips[_name];\n state.status = DripStatus.PAUSED;\n state.config.interval = _config.interval;\n state.config.dripcheck = _config.dripcheck;\n state.config.checkparams = _config.checkparams;\n\n // Solidity doesn't let us copy arrays into storage, so we push each array one by one.\n for (uint256 i = 0; i < _config.actions.length; i++) {\n state.config.actions.push(_config.actions[i]);\n }\n\n // Tell the world!\n emit DripCreated(_name, _config);\n }\n\n /**\n * Sets the status for a given drip. The behavior of this function depends on the status that\n * the user is trying to set. A drip can always move between ACTIVE and PAUSED, but it can\n * never move back to NONE and once ARCHIVED, it can never move back to ACTIVE or PAUSED.\n *\n * @param _name Name of the drip to update.\n * @param _status New drip status.\n */\n function status(string memory _name, DripStatus _status) external onlyOwner {\n // Make sure we can never set drip status back to NONE. A simple security measure to\n // prevent accidental overwrites if this code is ever updated down the line.\n require(\n _status != DripStatus.NONE,\n \"Drippie: drip status can never be set back to NONE after creation\"\n );\n\n // Make sure the drip in question actually exists. Not strictly necessary but there doesn't\n // seem to be any clear reason why you would want to do this, and it may save some gas in\n // the case of a front-end bug.\n require(\n drips[_name].status != DripStatus.NONE,\n \"Drippie: drip with that name does not exist\"\n );\n\n // Once a drip has been archived, it cannot be un-archived. This is, after all, the entire\n // point of archiving a drip.\n require(\n drips[_name].status != DripStatus.ARCHIVED,\n \"Drippie: drip with that name has been archived\"\n );\n\n // Although not strictly necessary, we make sure that the status here is actually changing.\n // This may save the client some gas if there's a front-end bug and the user accidentally\n // tries to \"change\" the status to the same value as before.\n require(\n drips[_name].status != _status,\n \"Drippie: cannot set drip status to same status as before\"\n );\n\n // If the user is trying to archive this drip, make sure the drip has been paused. We do\n // not allow users to archive active drips so that the effects of this action are more\n // abundantly clear.\n if (_status == DripStatus.ARCHIVED) {\n require(\n drips[_name].status == DripStatus.PAUSED,\n \"Drippie: drip must be paused to be archived\"\n );\n }\n\n // If we made it here then we can safely update the status.\n drips[_name].status = _status;\n emit DripStatusUpdated(_name, drips[_name].status);\n }\n\n /**\n * Triggers a drip. This function is deliberately left as a public function because the\n * assumption being made here is that setting the drip to ACTIVE is an affirmative signal that\n * the drip should be executable according to the drip parameters, drip check, and drip\n * interval. Note that drip parameters are read entirely from the state and are not supplied as\n * user input, so there should not be any way for a non-authorized user to influence the\n * behavior of the drip.\n *\n * @param _name Name of the drip to trigger.\n */\n function drip(string memory _name) external {\n DripState storage state = drips[_name];\n\n // Only allow active drips to be executed, an obvious security measure.\n require(\n state.status == DripStatus.ACTIVE,\n \"Drippie: selected drip does not exist or is not currently active\"\n );\n\n // Don't drip if the drip interval has not yet elapsed since the last time we dripped. This\n // is a safety measure that prevents a malicious recipient from, e.g., spending all of\n // their funds and repeatedly requesting new drips. Limits the potential impact of a\n // compromised recipient to just a single drip interval, after which the drip can be paused\n // by the owner address.\n require(\n state.last + state.config.interval <= block.timestamp,\n \"Drippie: drip interval has not elapsed since last drip\"\n );\n\n // Make sure we're allowed to execute this drip.\n require(\n state.config.dripcheck.check(state.config.checkparams),\n \"Drippie: dripcheck failed so drip is not yet ready to be triggered\"\n );\n\n // Update the last execution time for this drip before the call. Note that it's entirely\n // possible for a drip to be executed multiple times per block or even multiple times\n // within the same transaction (via re-entrancy) if the drip interval is set to zero. Users\n // should set a drip interval of 1 if they'd like the drip to be executed only once per\n // block (since this will then prevent re-entrancy).\n state.last = block.timestamp;\n\n // Execute each action in the drip. We allow drips to have multiple actions because there\n // are scenarios in which a contract must do multiple things atomically. For example, the\n // contract may need to withdraw ETH from one account and then deposit that ETH into\n // another account within the same transaction.\n uint256 len = state.config.actions.length;\n for (uint256 i = 0; i < len; i++) {\n // Must be marked as \"storage\" because copying structs into memory is not yet supported\n // by Solidity. Won't significantly reduce gas costs but at least makes it easier to\n // read what the rest of this section is doing.\n DripAction storage action = state.config.actions[i];\n\n // Actually execute the action. We could use ExcessivelySafeCall here but not strictly\n // necessary (worst case, a drip gets bricked IFF the target is malicious, doubt this\n // will ever happen in practice). Could save a marginal amount of gas to ignore the\n // returndata.\n // slither-disable-next-line calls-loop\n (bool success, ) = action.target.call{ value: action.value }(action.data);\n\n // Generally should not happen, but could if there's a misconfiguration (e.g., passing\n // the wrong data to the target contract), the recipient is not payable, or\n // insufficient gas was supplied to this transaction. We revert so the drip can be\n // fixed and triggered again later. Means we cannot emit an event to alert of the\n // failure, but can reasonably be detected by off-chain services even without an event.\n // Note that this forces the drip executor to supply sufficient gas to the call\n // (assuming there is some sufficient gas limit that exists, otherwise the drip will\n // not execute).\n require(\n success,\n \"Drippie: drip was unsuccessful, please check your configuration for mistakes\"\n );\n }\n\n emit DripExecuted(_name, msg.sender, block.timestamp);\n }\n}\n"
},
"contracts/universal/drippie/IDripCheck.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ninterface IDripCheck {\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\n // possible to easily encode parameters on the client side. Solidity does not support generics\n // so it's not possible to do this with explicit typing.\n\n function check(bytes memory _params) external view returns (bool);\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckTrue.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckTrue\n * @notice DripCheck that always returns true.\n */\ncontract CheckTrue is IDripCheck {\n function check(bytes memory) external pure returns (bool) {\n return true;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\ninterface IGelatoTreasury {\n function userTokenBalance(address _user, address _token) external view returns (uint256);\n}\n\n/**\n * @title CheckGelatoLow\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\n */\ncontract CheckGelatoLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address treasury;\n uint256 threshold;\n address recipient;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check GelatoTreasury ETH balance is below threshold.\n return\n IGelatoTreasury(params.treasury).userTokenBalance(\n params.recipient,\n // Gelato represents ETH as 0xeeeee....eeeee\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\n ) < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceLow\n * @notice DripCheck for checking if an account's balance is below a given threshold.\n */\ncontract CheckBalanceLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target ETH balance is below threshold.\n return params.target.balance < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceHigh\n * @notice DripCheck for checking if an account's balance is above a given threshold.\n */\ncontract CheckBalanceHigh is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target balance is above threshold.\n return params.target.balance > params.threshold;\n }\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
\ No newline at end of file
{
"language": "Solidity",
"sources": {
"contracts/universal/AssetReceiver.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\nimport { Transactor } from \"./Transactor.sol\";\n\n/**\n * @title AssetReceiver\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\n */\ncontract AssetReceiver is Transactor {\n /**\n * Emitted when ETH is received by this address.\n */\n event ReceivedETH(address indexed from, uint256 amount);\n\n /**\n * Emitted when ETH is withdrawn from this address.\n */\n event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\n\n /**\n * Emitted when ERC20 tokens are withdrawn from this address.\n */\n event WithdrewERC20(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 amount\n );\n\n /**\n * Emitted when ERC721 tokens are withdrawn from this address.\n */\n event WithdrewERC721(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 id\n );\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Transactor(_owner) {}\n\n /**\n * Make sure we can receive ETH.\n */\n receive() external payable {\n emit ReceivedETH(msg.sender, msg.value);\n }\n\n /**\n * Withdraws full ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n */\n function withdrawETH(address payable _to) external onlyOwner {\n withdrawETH(_to, address(this).balance);\n }\n\n /**\n * Withdraws partial ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n * @param _amount Amount of ETH to withdraw.\n */\n function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\n // slither-disable-next-line reentrancy-unlimited-gas\n _to.transfer(_amount);\n emit WithdrewETH(msg.sender, _to, _amount);\n }\n\n /**\n * Withdraws full ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n */\n function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\n withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\n }\n\n /**\n * Withdraws partial ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n * @param _amount Amount of ERC20 to withdraw.\n */\n function withdrawERC20(\n ERC20 _asset,\n address _to,\n uint256 _amount\n ) public onlyOwner {\n // slither-disable-next-line unchecked-transfer\n _asset.transfer(_to, _amount);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\n }\n\n /**\n * Withdraws ERC721 token to the recipient.\n *\n * @param _asset ERC721 token to withdraw.\n * @param _to Address to receive the ERC721 token.\n * @param _id Token ID of the ERC721 token to withdraw.\n */\n function withdrawERC721(\n ERC721 _asset,\n address _to,\n uint256 _id\n ) external onlyOwner {\n _asset.transferFrom(address(this), _to, _id);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC20.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n uint8 public immutable decimals;\n\n /*//////////////////////////////////////////////////////////////\n ERC20 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 public totalSupply;\n\n mapping(address => uint256) public balanceOf;\n\n mapping(address => mapping(address => uint256)) public allowance;\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal immutable INITIAL_CHAIN_ID;\n\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n mapping(address => uint256) public nonces;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals\n ) {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n INITIAL_CHAIN_ID = block.chainid;\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 amount) public virtual returns (bool) {\n allowance[msg.sender][spender] = amount;\n\n emit Approval(msg.sender, spender, amount);\n\n return true;\n }\n\n function transfer(address to, uint256 amount) public virtual returns (bool) {\n balanceOf[msg.sender] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(msg.sender, to, amount);\n\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual returns (bool) {\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n balanceOf[from] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual {\n require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n // Unchecked because the only math done is incrementing\n // the owner's nonce which cannot realistically overflow.\n unchecked {\n address recoveredAddress = ecrecover(\n keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(\n abi.encode(\n keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n ),\n owner,\n spender,\n value,\n nonces[owner]++,\n deadline\n )\n )\n )\n ),\n v,\n r,\n s\n );\n\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n allowance[recoveredAddress][spender] = value;\n }\n\n emit Approval(owner, spender, value);\n }\n\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n }\n\n function computeDomainSeparator() internal view virtual returns (bytes32) {\n return\n keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(name)),\n keccak256(\"1\"),\n block.chainid,\n address(this)\n )\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 amount) internal virtual {\n totalSupply += amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal virtual {\n balanceOf[from] -= amount;\n\n // Cannot underflow because a user's balance\n // will never be larger than the total supply.\n unchecked {\n totalSupply -= amount;\n }\n\n emit Transfer(from, address(0), amount);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC721.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) internal _ownerOf;\n\n mapping(address => uint256) internal _balanceOf;\n\n function ownerOf(uint256 id) public view virtual returns (address owner) {\n require((owner = _ownerOf[id]) != address(0), \"NOT_MINTED\");\n }\n\n function balanceOf(address owner) public view virtual returns (uint256) {\n require(owner != address(0), \"ZERO_ADDRESS\");\n\n return _balanceOf[owner];\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) public getApproved;\n\n mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 id) public virtual {\n address owner = _ownerOf[id];\n\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n getApproved[id] = spender;\n\n emit Approval(owner, spender, id);\n }\n\n function setApprovalForAll(address operator, bool approved) public virtual {\n isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n require(from == _ownerOf[id], \"WRONG_FROM\");\n\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(\n msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\n \"NOT_AUTHORIZED\"\n );\n\n // Underflow of the sender's balance is impossible because we check for\n // ownership above and the recipient's balance can't realistically overflow.\n unchecked {\n _balanceOf[from]--;\n\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n delete getApproved[id];\n\n emit Transfer(from, to, id);\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n transferFrom(from, to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n bytes calldata data\n ) public virtual {\n transferFrom(from, to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 id) internal virtual {\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(_ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n // Counter overflow is incredibly unrealistic.\n unchecked {\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n emit Transfer(address(0), to, id);\n }\n\n function _burn(uint256 id) internal virtual {\n address owner = _ownerOf[id];\n\n require(owner != address(0), \"NOT_MINTED\");\n\n // Ownership check above ensures no underflow.\n unchecked {\n _balanceOf[owner]--;\n }\n\n delete _ownerOf[id];\n\n delete getApproved[id];\n\n emit Transfer(owner, address(0), id);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL SAFE MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _safeMint(address to, uint256 id) internal virtual {\n _mint(to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _safeMint(\n address to,\n uint256 id,\n bytes memory data\n ) internal virtual {\n _mint(to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721TokenReceiver {\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external virtual returns (bytes4) {\n return ERC721TokenReceiver.onERC721Received.selector;\n }\n}\n"
},
"contracts/universal/Transactor.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { Owned } from \"@rari-capital/solmate/src/auth/Owned.sol\";\n\n/**\n * @title Transactor\n * @notice Transactor is a minimal contract that can send transactions.\n */\ncontract Transactor is Owned {\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Owned(_owner) {}\n\n /**\n * Sends a CALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @param _value ETH value to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function CALL(\n address _target,\n bytes memory _data,\n uint256 _gas,\n uint256 _value\n ) external payable onlyOwner returns (bool, bytes memory) {\n return _target.call{ gas: _gas, value: _value }(_data);\n }\n\n /**\n * Sends a DELEGATECALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function DELEGATECALL(\n address _target,\n bytes memory _data,\n uint256 _gas\n ) external payable onlyOwner returns (bool, bytes memory) {\n // slither-disable-next-line controlled-delegatecall\n return _target.delegatecall{ gas: _gas }(_data);\n }\n}\n"
},
"@rari-capital/solmate/src/auth/Owned.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event OwnerUpdated(address indexed user, address indexed newOwner);\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP STORAGE\n //////////////////////////////////////////////////////////////*/\n\n address public owner;\n\n modifier onlyOwner() virtual {\n require(msg.sender == owner, \"UNAUTHORIZED\");\n\n _;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address _owner) {\n owner = _owner;\n\n emit OwnerUpdated(address(0), _owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function setOwner(address newOwner) public virtual onlyOwner {\n owner = newOwner;\n\n emit OwnerUpdated(msg.sender, newOwner);\n }\n}\n"
},
"contracts/universal/drippie/Drippie.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { AssetReceiver } from \"../AssetReceiver.sol\";\nimport { IDripCheck } from \"./IDripCheck.sol\";\n\n/**\n * @title Drippie\n * @notice Drippie is a system for managing automated contract interactions. A specific interaction\n * is called a \"drip\" and can be executed according to some condition (called a dripcheck) and an\n * execution interval. Drips cannot be executed faster than the execution interval. Drips can\n * trigger arbitrary contract calls where the calling contract is this contract address. Drips can\n * also send ETH value, which makes them ideal for keeping addresses sufficiently funded with ETH.\n * Drippie is designed to be connected with smart contract automation services so that drips can be\n * executed automatically. However, Drippie is specifically designed to be separated from these\n * services so that trust assumptions are better compartmentalized.\n */\ncontract Drippie is AssetReceiver {\n /**\n * Enum representing different status options for a given drip.\n */\n enum DripStatus {\n NONE,\n ACTIVE,\n PAUSED,\n ARCHIVED\n }\n\n /**\n * Represents a drip action.\n */\n struct DripAction {\n address payable target;\n bytes data;\n uint256 value;\n }\n\n /**\n * Represents the configuration for a given drip.\n */\n struct DripConfig {\n uint256 interval;\n IDripCheck dripcheck;\n bytes checkparams;\n DripAction[] actions;\n }\n\n /**\n * Represents the state of an active drip.\n */\n struct DripState {\n DripStatus status;\n DripConfig config;\n uint256 last;\n }\n\n /**\n * Emitted when a new drip is created.\n */\n event DripCreated(string indexed name, DripConfig config);\n\n /**\n * Emitted when a drip status is updated.\n */\n event DripStatusUpdated(string indexed name, DripStatus status);\n\n /**\n * Emitted when a drip is executed.\n */\n event DripExecuted(string indexed name, address indexed executor, uint256 timestamp);\n\n /**\n * Maps from drip names to drip states.\n */\n mapping(string => DripState) public drips;\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) AssetReceiver(_owner) {}\n\n /**\n * Creates a new drip with the given name and configuration. Once created, drips cannot be\n * modified in any way (this is a security measure). If you want to update a drip, simply pause\n * (and potentially archive) the existing drip and create a new one.\n *\n * @param _name Name of the drip.\n * @param _config Configuration for the drip.\n */\n function create(string memory _name, DripConfig memory _config) external onlyOwner {\n // Make sure this drip doesn't already exist. We *must* guarantee that no other function\n // will ever set the status of a drip back to NONE after it's been created. This is why\n // archival is a separate status.\n require(\n drips[_name].status == DripStatus.NONE,\n \"Drippie: drip with that name already exists\"\n );\n\n // We initialize this way because Solidity won't let us copy arrays into storage yet.\n DripState storage state = drips[_name];\n state.status = DripStatus.PAUSED;\n state.config.interval = _config.interval;\n state.config.dripcheck = _config.dripcheck;\n state.config.checkparams = _config.checkparams;\n\n // Solidity doesn't let us copy arrays into storage, so we push each array one by one.\n for (uint256 i = 0; i < _config.actions.length; i++) {\n state.config.actions.push(_config.actions[i]);\n }\n\n // Tell the world!\n emit DripCreated(_name, _config);\n }\n\n /**\n * Sets the status for a given drip. The behavior of this function depends on the status that\n * the user is trying to set. A drip can always move between ACTIVE and PAUSED, but it can\n * never move back to NONE and once ARCHIVED, it can never move back to ACTIVE or PAUSED.\n *\n * @param _name Name of the drip to update.\n * @param _status New drip status.\n */\n function status(string memory _name, DripStatus _status) external onlyOwner {\n // Make sure we can never set drip status back to NONE. A simple security measure to\n // prevent accidental overwrites if this code is ever updated down the line.\n require(\n _status != DripStatus.NONE,\n \"Drippie: drip status can never be set back to NONE after creation\"\n );\n\n // Make sure the drip in question actually exists. Not strictly necessary but there doesn't\n // seem to be any clear reason why you would want to do this, and it may save some gas in\n // the case of a front-end bug.\n require(\n drips[_name].status != DripStatus.NONE,\n \"Drippie: drip with that name does not exist\"\n );\n\n // Once a drip has been archived, it cannot be un-archived. This is, after all, the entire\n // point of archiving a drip.\n require(\n drips[_name].status != DripStatus.ARCHIVED,\n \"Drippie: drip with that name has been archived\"\n );\n\n // Although not strictly necessary, we make sure that the status here is actually changing.\n // This may save the client some gas if there's a front-end bug and the user accidentally\n // tries to \"change\" the status to the same value as before.\n require(\n drips[_name].status != _status,\n \"Drippie: cannot set drip status to same status as before\"\n );\n\n // If the user is trying to archive this drip, make sure the drip has been paused. We do\n // not allow users to archive active drips so that the effects of this action are more\n // abundantly clear.\n if (_status == DripStatus.ARCHIVED) {\n require(\n drips[_name].status == DripStatus.PAUSED,\n \"Drippie: drip must be paused to be archived\"\n );\n }\n\n // If we made it here then we can safely update the status.\n drips[_name].status = _status;\n emit DripStatusUpdated(_name, drips[_name].status);\n }\n\n /**\n * Triggers a drip. This function is deliberately left as a public function because the\n * assumption being made here is that setting the drip to ACTIVE is an affirmative signal that\n * the drip should be executable according to the drip parameters, drip check, and drip\n * interval. Note that drip parameters are read entirely from the state and are not supplied as\n * user input, so there should not be any way for a non-authorized user to influence the\n * behavior of the drip.\n *\n * @param _name Name of the drip to trigger.\n */\n function drip(string memory _name) external {\n DripState storage state = drips[_name];\n\n // Only allow active drips to be executed, an obvious security measure.\n require(\n state.status == DripStatus.ACTIVE,\n \"Drippie: selected drip does not exist or is not currently active\"\n );\n\n // Don't drip if the drip interval has not yet elapsed since the last time we dripped. This\n // is a safety measure that prevents a malicious recipient from, e.g., spending all of\n // their funds and repeatedly requesting new drips. Limits the potential impact of a\n // compromised recipient to just a single drip interval, after which the drip can be paused\n // by the owner address.\n require(\n state.last + state.config.interval <= block.timestamp,\n \"Drippie: drip interval has not elapsed since last drip\"\n );\n\n // Make sure we're allowed to execute this drip.\n require(\n state.config.dripcheck.check(state.config.checkparams),\n \"Drippie: dripcheck failed so drip is not yet ready to be triggered\"\n );\n\n // Update the last execution time for this drip before the call. Note that it's entirely\n // possible for a drip to be executed multiple times per block or even multiple times\n // within the same transaction (via re-entrancy) if the drip interval is set to zero. Users\n // should set a drip interval of 1 if they'd like the drip to be executed only once per\n // block (since this will then prevent re-entrancy).\n state.last = block.timestamp;\n\n // Execute each action in the drip. We allow drips to have multiple actions because there\n // are scenarios in which a contract must do multiple things atomically. For example, the\n // contract may need to withdraw ETH from one account and then deposit that ETH into\n // another account within the same transaction.\n uint256 len = state.config.actions.length;\n for (uint256 i = 0; i < len; i++) {\n // Must be marked as \"storage\" because copying structs into memory is not yet supported\n // by Solidity. Won't significantly reduce gas costs but at least makes it easier to\n // read what the rest of this section is doing.\n DripAction storage action = state.config.actions[i];\n\n // Actually execute the action. We could use ExcessivelySafeCall here but not strictly\n // necessary (worst case, a drip gets bricked IFF the target is malicious, doubt this\n // will ever happen in practice). Could save a marginal amount of gas to ignore the\n // returndata.\n // slither-disable-next-line calls-loop\n (bool success, ) = action.target.call{ value: action.value }(action.data);\n\n // Generally should not happen, but could if there's a misconfiguration (e.g., passing\n // the wrong data to the target contract), the recipient is not payable, or\n // insufficient gas was supplied to this transaction. We revert so the drip can be\n // fixed and triggered again later. Means we cannot emit an event to alert of the\n // failure, but can reasonably be detected by off-chain services even without an event.\n // Note that this forces the drip executor to supply sufficient gas to the call\n // (assuming there is some sufficient gas limit that exists, otherwise the drip will\n // not execute).\n require(\n success,\n \"Drippie: drip was unsuccessful, please check your configuration for mistakes\"\n );\n }\n\n emit DripExecuted(_name, msg.sender, block.timestamp);\n }\n}\n"
},
"contracts/universal/drippie/IDripCheck.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ninterface IDripCheck {\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\n // possible to easily encode parameters on the client side. Solidity does not support generics\n // so it's not possible to do this with explicit typing.\n\n function check(bytes memory _params) external view returns (bool);\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckTrue.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckTrue\n * @notice DripCheck that always returns true.\n */\ncontract CheckTrue is IDripCheck {\n function check(bytes memory) external pure returns (bool) {\n return true;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\ninterface IGelatoTreasury {\n function userTokenBalance(address _user, address _token) external view returns (uint256);\n}\n\n/**\n * @title CheckGelatoLow\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\n */\ncontract CheckGelatoLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address treasury;\n uint256 threshold;\n address recipient;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check GelatoTreasury ETH balance is below threshold.\n return\n IGelatoTreasury(params.treasury).userTokenBalance(\n params.recipient,\n // Gelato represents ETH as 0xeeeee....eeeee\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\n ) < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceLow\n * @notice DripCheck for checking if an account's balance is below a given threshold.\n */\ncontract CheckBalanceLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target ETH balance is below threshold.\n return params.target.balance < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceHigh\n * @notice DripCheck for checking if an account's balance is above a given threshold.\n */\ncontract CheckBalanceHigh is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target balance is above threshold.\n return params.target.balance > params.threshold;\n }\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"language": "Solidity",
"sources": {
"contracts/universal/op-nft/AttestationStation.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.15;\n\nimport { Semver } from \"@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol\";\n\n/**\n * @title AttestationStation\n * @author Optimism Collective\n * @author Gitcoin\n * @notice Where attestations live.\n */\ncontract AttestationStation is Semver {\n /**\n * @notice Struct representing data that is being attested.\n *\n * @custom:field about Address for which the attestation is about.\n * @custom:field key A bytes32 key for the attestation.\n * @custom:field val The attestation as arbitrary bytes.\n */\n struct AttestationData {\n address about;\n bytes32 key;\n bytes val;\n }\n\n /**\n * @notice Maps addresses to attestations. Creator => About => Key => Value.\n */\n mapping(address => mapping(address => mapping(bytes32 => bytes))) public attestations;\n\n /**\n * @notice Emitted when Attestation is created.\n *\n * @param creator Address that made the attestation.\n * @param about Address attestation is about.\n * @param key Key of the attestation.\n * @param val Value of the attestation.\n */\n event AttestationCreated(\n address indexed creator,\n address indexed about,\n bytes32 indexed key,\n bytes val\n );\n\n /**\n * @custom:semver 1.1.0\n */\n constructor() Semver(1, 1, 0) {}\n\n /**\n * @notice Allows anyone to create an attestation.\n *\n * @param _about Address that the attestation is about.\n * @param _key A key used to namespace the attestation.\n * @param _val An arbitrary value stored as part of the attestation.\n */\n function attest(\n address _about,\n bytes32 _key,\n bytes memory _val\n ) public {\n attestations[msg.sender][_about][_key] = _val;\n\n emit AttestationCreated(msg.sender, _about, _key, _val);\n }\n\n /**\n * @notice Allows anyone to create attestations.\n *\n * @param _attestations An array of attestation data.\n */\n function attest(AttestationData[] calldata _attestations) external {\n uint256 length = _attestations.length;\n for (uint256 i = 0; i < length; ) {\n AttestationData memory attestation = _attestations[i];\n\n attest(attestation.about, attestation.key, attestation.val);\n\n unchecked {\n ++i;\n }\n }\n }\n}\n"
},
"@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.15;\n\nimport { Strings } from \"@openzeppelin/contracts/utils/Strings.sol\";\n\n/**\n * @title Semver\n * @notice Semver is a simple contract for managing contract versions.\n */\ncontract Semver {\n /**\n * @notice Contract version number (major).\n */\n uint256 private immutable MAJOR_VERSION;\n\n /**\n * @notice Contract version number (minor).\n */\n uint256 private immutable MINOR_VERSION;\n\n /**\n * @notice Contract version number (patch).\n */\n uint256 private immutable PATCH_VERSION;\n\n /**\n * @param _major Version number (major).\n * @param _minor Version number (minor).\n * @param _patch Version number (patch).\n */\n constructor(\n uint256 _major,\n uint256 _minor,\n uint256 _patch\n ) {\n MAJOR_VERSION = _major;\n MINOR_VERSION = _minor;\n PATCH_VERSION = _patch;\n }\n\n /**\n * @notice Returns the full semver contract version.\n *\n * @return Semver contract version as a string.\n */\n function version() public view returns (string memory) {\n return\n string(\n abi.encodePacked(\n Strings.toString(MAJOR_VERSION),\n \".\",\n Strings.toString(MINOR_VERSION),\n \".\",\n Strings.toString(PATCH_VERSION)\n )\n );\n }\n}\n"
},
"@openzeppelin/contracts/utils/Strings.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n"
},
"contracts/universal/op-nft/Optimist.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.15;\n\nimport { Semver } from \"@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol\";\nimport {\n ERC721BurnableUpgradeable\n} from \"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol\";\nimport { AttestationStation } from \"./AttestationStation.sol\";\nimport { Strings } from \"@openzeppelin/contracts/utils/Strings.sol\";\n\n/**\n * @author Optimism Collective\n * @author Gitcoin\n * @title Optimist\n * @notice A Soul Bound Token for real humans only(tm).\n */\ncontract Optimist is ERC721BurnableUpgradeable, Semver {\n /**\n * @notice Address of the AttestationStation contract.\n */\n AttestationStation public immutable ATTESTATION_STATION;\n\n /**\n * @notice Attestor who attests to baseURI and allowlist.\n */\n address public immutable ATTESTOR;\n\n /**\n * @custom:semver 1.0.0\n * @param _name Token name.\n * @param _symbol Token symbol.\n * @param _attestor Address of the attestor.\n * @param _attestationStation Address of the AttestationStation contract.\n */\n constructor(\n string memory _name,\n string memory _symbol,\n address _attestor,\n AttestationStation _attestationStation\n ) Semver(1, 0, 0) {\n ATTESTOR = _attestor;\n ATTESTATION_STATION = _attestationStation;\n initialize(_name, _symbol);\n }\n\n /**\n * @notice Initializes the Optimist contract.\n *\n * @param _name Token name.\n * @param _symbol Token symbol.\n */\n function initialize(string memory _name, string memory _symbol) public initializer {\n __ERC721_init(_name, _symbol);\n __ERC721Burnable_init();\n }\n\n /**\n * @notice Allows an address to mint an Optimist NFT. Token ID is the uint256 representation\n * of the recipient's address. Recipients must be permitted to mint, eventually anyone\n * will be able to mint. One token per address.\n *\n * @param _recipient Address of the token recipient.\n */\n function mint(address _recipient) public {\n require(isOnAllowList(_recipient), \"Optimist: address is not on allowList\");\n _safeMint(_recipient, tokenIdOfAddress(_recipient));\n }\n\n /**\n * @notice Returns the baseURI for all tokens.\n *\n * @return BaseURI for all tokens.\n */\n function baseURI() public view returns (string memory) {\n return\n string(\n abi.encodePacked(\n ATTESTATION_STATION.attestations(\n ATTESTOR,\n address(this),\n bytes32(\"optimist.base-uri\")\n )\n )\n );\n }\n\n /**\n * @notice Returns the token URI for a given token by ID\n *\n * @param _tokenId Token ID to query.\n\n * @return Token URI for the given token by ID.\n */\n function tokenURI(uint256 _tokenId) public view virtual override returns (string memory) {\n return\n string(\n abi.encodePacked(\n baseURI(),\n \"/\",\n // Properly format the token ID as a 20 byte hex string (address).\n Strings.toHexString(_tokenId, 20),\n \".json\"\n )\n );\n }\n\n /**\n * @notice Checks whether a given address is allowed to mint the Optimist NFT yet. Since the\n * Optimist NFT will also be used as part of the Citizens House, mints are currently\n * restricted. Eventually anyone will be able to mint.\n *\n * @return Whether or not the address is allowed to mint yet.\n */\n function isOnAllowList(address _recipient) public view returns (bool) {\n return\n ATTESTATION_STATION\n .attestations(ATTESTOR, _recipient, bytes32(\"optimist.can-mint\"))\n .length > 0;\n }\n\n /**\n * @notice Returns the token ID for the token owned by a given address. This is the uint256\n * representation of the given address.\n *\n * @return Token ID for the token owned by the given address.\n */\n function tokenIdOfAddress(address _owner) public pure returns (uint256) {\n return uint256(uint160(_owner));\n }\n\n /**\n * @notice Disabled for the Optimist NFT (Soul Bound Token).\n */\n function approve(address, uint256) public pure override {\n revert(\"Optimist: soul bound token\");\n }\n\n /**\n * @notice Disabled for the Optimist NFT (Soul Bound Token).\n */\n function setApprovalForAll(address, bool) public virtual override {\n revert(\"Optimist: soul bound token\");\n }\n\n /**\n * @notice Prevents transfers of the Optimist NFT (Soul Bound Token).\n *\n * @param _from Address of the token sender.\n * @param _to Address of the token recipient.\n */\n function _beforeTokenTransfer(\n address _from,\n address _to,\n uint256\n ) internal virtual override {\n require(_from == address(0) || _to == address(0), \"Optimist: soul bound token\");\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/extensions/ERC721Burnable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC721Upgradeable.sol\";\nimport \"../../../utils/ContextUpgradeable.sol\";\nimport \"../../../proxy/utils/Initializable.sol\";\n\n/**\n * @title ERC721 Burnable Token\n * @dev ERC721 Token that can be burned (destroyed).\n */\nabstract contract ERC721BurnableUpgradeable is Initializable, ContextUpgradeable, ERC721Upgradeable {\n function __ERC721Burnable_init() internal onlyInitializing {\n }\n\n function __ERC721Burnable_init_unchained() internal onlyInitializing {\n }\n /**\n * @dev Burns `tokenId`. See {ERC721-_burn}.\n *\n * Requirements:\n *\n * - The caller must own `tokenId` or be an approved operator.\n */\n function burn(uint256 tokenId) public virtual {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner nor approved\");\n _burn(tokenId);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n"
},
"@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721Upgradeable.sol\";\nimport \"./IERC721ReceiverUpgradeable.sol\";\nimport \"./extensions/IERC721MetadataUpgradeable.sol\";\nimport \"../../utils/AddressUpgradeable.sol\";\nimport \"../../utils/ContextUpgradeable.sol\";\nimport \"../../utils/StringsUpgradeable.sol\";\nimport \"../../utils/introspection/ERC165Upgradeable.sol\";\nimport \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable {\n using AddressUpgradeable for address;\n using StringsUpgradeable for uint256;\n\n // Token name\n string private _name;\n\n // Token symbol\n string private _symbol;\n\n // Mapping from token ID to owner address\n mapping(uint256 => address) private _owners;\n\n // Mapping owner address to token count\n mapping(address => uint256) private _balances;\n\n // Mapping from token ID to approved address\n mapping(uint256 => address) private _tokenApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n /**\n * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n */\n function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing {\n __ERC721_init_unchained(name_, symbol_);\n }\n\n function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) {\n return\n interfaceId == type(IERC721Upgradeable).interfaceId ||\n interfaceId == type(IERC721MetadataUpgradeable).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev See {IERC721-balanceOf}.\n */\n function balanceOf(address owner) public view virtual override returns (uint256) {\n require(owner != address(0), \"ERC721: address zero is not a valid owner\");\n return _balances[owner];\n }\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n address owner = _owners[tokenId];\n require(owner != address(0), \"ERC721: invalid token ID\");\n return owner;\n }\n\n /**\n * @dev See {IERC721Metadata-name}.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev See {IERC721Metadata-symbol}.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev See {IERC721Metadata-tokenURI}.\n */\n function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n _requireMinted(tokenId);\n\n string memory baseURI = _baseURI();\n return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n }\n\n /**\n * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n * by default, can be overridden in child contracts.\n */\n function _baseURI() internal view virtual returns (string memory) {\n return \"\";\n }\n\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) public virtual override {\n address owner = ERC721Upgradeable.ownerOf(tokenId);\n require(to != owner, \"ERC721: approval to current owner\");\n\n require(\n _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n \"ERC721: approve caller is not token owner nor approved for all\"\n );\n\n _approve(to, tokenId);\n }\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) public view virtual override returns (address) {\n _requireMinted(tokenId);\n\n return _tokenApprovals[tokenId];\n }\n\n /**\n * @dev See {IERC721-setApprovalForAll}.\n */\n function setApprovalForAll(address operator, bool approved) public virtual override {\n _setApprovalForAll(_msgSender(), operator, approved);\n }\n\n /**\n * @dev See {IERC721-isApprovedForAll}.\n */\n function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n return _operatorApprovals[owner][operator];\n }\n\n /**\n * @dev See {IERC721-transferFrom}.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner nor approved\");\n\n _transfer(from, to, tokenId);\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n safeTransferFrom(from, to, tokenId, \"\");\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) public virtual override {\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner nor approved\");\n _safeTransfer(from, to, tokenId, data);\n }\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * `data` is additional data, it has no specified format and it is sent in call to `to`.\n *\n * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n * implement alternative mechanisms to perform token transfer, such as signature-based.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeTransfer(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) internal virtual {\n _transfer(from, to, tokenId);\n require(_checkOnERC721Received(from, to, tokenId, data), \"ERC721: transfer to non ERC721Receiver implementer\");\n }\n\n /**\n * @dev Returns whether `tokenId` exists.\n *\n * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n *\n * Tokens start existing when they are minted (`_mint`),\n * and stop existing when they are burned (`_burn`).\n */\n function _exists(uint256 tokenId) internal view virtual returns (bool) {\n return _owners[tokenId] != address(0);\n }\n\n /**\n * @dev Returns whether `spender` is allowed to manage `tokenId`.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n address owner = ERC721Upgradeable.ownerOf(tokenId);\n return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);\n }\n\n /**\n * @dev Safely mints `tokenId` and transfers it to `to`.\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeMint(address to, uint256 tokenId) internal virtual {\n _safeMint(to, tokenId, \"\");\n }\n\n /**\n * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n */\n function _safeMint(\n address to,\n uint256 tokenId,\n bytes memory data\n ) internal virtual {\n _mint(to, tokenId);\n require(\n _checkOnERC721Received(address(0), to, tokenId, data),\n \"ERC721: transfer to non ERC721Receiver implementer\"\n );\n }\n\n /**\n * @dev Mints `tokenId` and transfers it to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - `to` cannot be the zero address.\n *\n * Emits a {Transfer} event.\n */\n function _mint(address to, uint256 tokenId) internal virtual {\n require(to != address(0), \"ERC721: mint to the zero address\");\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n _beforeTokenTransfer(address(0), to, tokenId);\n\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(address(0), to, tokenId);\n\n _afterTokenTransfer(address(0), to, tokenId);\n }\n\n /**\n * @dev Destroys `tokenId`.\n * The approval is cleared when the token is burned.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n *\n * Emits a {Transfer} event.\n */\n function _burn(uint256 tokenId) internal virtual {\n address owner = ERC721Upgradeable.ownerOf(tokenId);\n\n _beforeTokenTransfer(owner, address(0), tokenId);\n\n // Clear approvals\n _approve(address(0), tokenId);\n\n _balances[owner] -= 1;\n delete _owners[tokenId];\n\n emit Transfer(owner, address(0), tokenId);\n\n _afterTokenTransfer(owner, address(0), tokenId);\n }\n\n /**\n * @dev Transfers `tokenId` from `from` to `to`.\n * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n *\n * Emits a {Transfer} event.\n */\n function _transfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {\n require(ERC721Upgradeable.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n require(to != address(0), \"ERC721: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, tokenId);\n\n // Clear approvals from the previous owner\n _approve(address(0), tokenId);\n\n _balances[from] -= 1;\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(from, to, tokenId);\n\n _afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Approve `to` to operate on `tokenId`\n *\n * Emits an {Approval} event.\n */\n function _approve(address to, uint256 tokenId) internal virtual {\n _tokenApprovals[tokenId] = to;\n emit Approval(ERC721Upgradeable.ownerOf(tokenId), to, tokenId);\n }\n\n /**\n * @dev Approve `operator` to operate on all of `owner` tokens\n *\n * Emits an {ApprovalForAll} event.\n */\n function _setApprovalForAll(\n address owner,\n address operator,\n bool approved\n ) internal virtual {\n require(owner != operator, \"ERC721: approve to caller\");\n _operatorApprovals[owner][operator] = approved;\n emit ApprovalForAll(owner, operator, approved);\n }\n\n /**\n * @dev Reverts if the `tokenId` has not been minted yet.\n */\n function _requireMinted(uint256 tokenId) internal view virtual {\n require(_exists(tokenId), \"ERC721: invalid token ID\");\n }\n\n /**\n * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n * The call is not executed if the target address is not a contract.\n *\n * @param from address representing the previous owner of the given token ID\n * @param to target address that will receive the tokens\n * @param tokenId uint256 ID of the token to be transferred\n * @param data bytes optional data to send along with the call\n * @return bool whether the call correctly returned the expected magic value\n */\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721ReceiverUpgradeable(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {\n return retval == IERC721ReceiverUpgradeable.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n } else {\n /// @solidity memory-safe-assembly\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /**\n * @dev Hook that is called before any token transfer. This includes minting\n * and burning.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be\n * transferred to `to`.\n * - When `from` is zero, `tokenId` will be minted for `to`.\n * - When `to` is zero, ``from``'s `tokenId` will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[44] private __gap;\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n"
},
"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n * initialization step. This is essential to configure modules that are added through upgrades and that require\n * initialization.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized < type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165Upgradeable.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721Upgradeable is IERC165Upgradeable {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
},
"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721ReceiverUpgradeable {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n"
},
"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721Upgradeable.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721MetadataUpgradeable is IERC721Upgradeable {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary StringsUpgradeable {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165Upgradeable.sol\";\nimport \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {\n function __ERC165_init() internal onlyInitializing {\n }\n\n function __ERC165_init_unchained() internal onlyInitializing {\n }\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165Upgradeable).interfaceId;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165Upgradeable {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
\ No newline at end of file
{
"language": "Solidity",
"sources": {
"contracts/universal/op-nft/AttestationStation.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.15;\n\nimport { Semver } from \"@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol\";\n\n/**\n * @title AttestationStation\n * @author Optimism Collective\n * @author Gitcoin\n * @notice Where attestations live.\n */\ncontract AttestationStation is Semver {\n /**\n * @notice Struct representing data that is being attested.\n *\n * @custom:field about Address for which the attestation is about.\n * @custom:field key A bytes32 key for the attestation.\n * @custom:field val The attestation as arbitrary bytes.\n */\n struct AttestationData {\n address about;\n bytes32 key;\n bytes val;\n }\n\n /**\n * @notice Maps addresses to attestations. Creator => About => Key => Value.\n */\n mapping(address => mapping(address => mapping(bytes32 => bytes))) public attestations;\n\n /**\n * @notice Emitted when Attestation is created.\n *\n * @param creator Address that made the attestation.\n * @param about Address attestation is about.\n * @param key Key of the attestation.\n * @param val Value of the attestation.\n */\n event AttestationCreated(\n address indexed creator,\n address indexed about,\n bytes32 indexed key,\n bytes val\n );\n\n /**\n * @custom:semver 1.1.0\n */\n constructor() Semver(1, 1, 0) {}\n\n /**\n * @notice Allows anyone to create an attestation.\n *\n * @param _about Address that the attestation is about.\n * @param _key A key used to namespace the attestation.\n * @param _val An arbitrary value stored as part of the attestation.\n */\n function attest(\n address _about,\n bytes32 _key,\n bytes memory _val\n ) public {\n attestations[msg.sender][_about][_key] = _val;\n\n emit AttestationCreated(msg.sender, _about, _key, _val);\n }\n\n /**\n * @notice Allows anyone to create attestations.\n *\n * @param _attestations An array of attestation data.\n */\n function attest(AttestationData[] calldata _attestations) external {\n uint256 length = _attestations.length;\n for (uint256 i = 0; i < length; ) {\n AttestationData memory attestation = _attestations[i];\n\n attest(attestation.about, attestation.key, attestation.val);\n\n unchecked {\n ++i;\n }\n }\n }\n}\n"
},
"@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.15;\n\nimport { Strings } from \"@openzeppelin/contracts/utils/Strings.sol\";\n\n/**\n * @title Semver\n * @notice Semver is a simple contract for managing contract versions.\n */\ncontract Semver {\n /**\n * @notice Contract version number (major).\n */\n uint256 private immutable MAJOR_VERSION;\n\n /**\n * @notice Contract version number (minor).\n */\n uint256 private immutable MINOR_VERSION;\n\n /**\n * @notice Contract version number (patch).\n */\n uint256 private immutable PATCH_VERSION;\n\n /**\n * @param _major Version number (major).\n * @param _minor Version number (minor).\n * @param _patch Version number (patch).\n */\n constructor(\n uint256 _major,\n uint256 _minor,\n uint256 _patch\n ) {\n MAJOR_VERSION = _major;\n MINOR_VERSION = _minor;\n PATCH_VERSION = _patch;\n }\n\n /**\n * @notice Returns the full semver contract version.\n *\n * @return Semver contract version as a string.\n */\n function version() public view returns (string memory) {\n return\n string(\n abi.encodePacked(\n Strings.toString(MAJOR_VERSION),\n \".\",\n Strings.toString(MINOR_VERSION),\n \".\",\n Strings.toString(PATCH_VERSION)\n )\n );\n }\n}\n"
},
"@openzeppelin/contracts/utils/Strings.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary Strings {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n"
},
"contracts/universal/op-nft/Optimist.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity 0.8.15;\n\nimport { Semver } from \"@eth-optimism/contracts-bedrock/contracts/universal/Semver.sol\";\nimport {\n ERC721BurnableUpgradeable\n} from \"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol\";\nimport { AttestationStation } from \"./AttestationStation.sol\";\nimport { Strings } from \"@openzeppelin/contracts/utils/Strings.sol\";\n\n/**\n * @author Optimism Collective\n * @author Gitcoin\n * @title Optimist\n * @notice A Soul Bound Token for real humans only(tm).\n */\ncontract Optimist is ERC721BurnableUpgradeable, Semver {\n /**\n * @notice Address of the AttestationStation contract.\n */\n AttestationStation public immutable ATTESTATION_STATION;\n\n /**\n * @notice Attestor who attests to baseURI and allowlist.\n */\n address public immutable ATTESTOR;\n\n /**\n * @custom:semver 1.0.0\n * @param _name Token name.\n * @param _symbol Token symbol.\n * @param _attestor Address of the attestor.\n * @param _attestationStation Address of the AttestationStation contract.\n */\n constructor(\n string memory _name,\n string memory _symbol,\n address _attestor,\n AttestationStation _attestationStation\n ) Semver(1, 0, 0) {\n ATTESTOR = _attestor;\n ATTESTATION_STATION = _attestationStation;\n initialize(_name, _symbol);\n }\n\n /**\n * @notice Initializes the Optimist contract.\n *\n * @param _name Token name.\n * @param _symbol Token symbol.\n */\n function initialize(string memory _name, string memory _symbol) public initializer {\n __ERC721_init(_name, _symbol);\n __ERC721Burnable_init();\n }\n\n /**\n * @notice Allows an address to mint an Optimist NFT. Token ID is the uint256 representation\n * of the recipient's address. Recipients must be permitted to mint, eventually anyone\n * will be able to mint. One token per address.\n *\n * @param _recipient Address of the token recipient.\n */\n function mint(address _recipient) public {\n require(isOnAllowList(_recipient), \"Optimist: address is not on allowList\");\n _safeMint(_recipient, tokenIdOfAddress(_recipient));\n }\n\n /**\n * @notice Returns the baseURI for all tokens.\n *\n * @return BaseURI for all tokens.\n */\n function baseURI() public view returns (string memory) {\n return\n string(\n abi.encodePacked(\n ATTESTATION_STATION.attestations(\n ATTESTOR,\n address(this),\n bytes32(\"optimist.base-uri\")\n )\n )\n );\n }\n\n /**\n * @notice Returns the token URI for a given token by ID\n *\n * @param _tokenId Token ID to query.\n\n * @return Token URI for the given token by ID.\n */\n function tokenURI(uint256 _tokenId) public view virtual override returns (string memory) {\n return\n string(\n abi.encodePacked(\n baseURI(),\n \"/\",\n // Properly format the token ID as a 20 byte hex string (address).\n Strings.toHexString(_tokenId, 20),\n \".json\"\n )\n );\n }\n\n /**\n * @notice Checks whether a given address is allowed to mint the Optimist NFT yet. Since the\n * Optimist NFT will also be used as part of the Citizens House, mints are currently\n * restricted. Eventually anyone will be able to mint.\n *\n * @return Whether or not the address is allowed to mint yet.\n */\n function isOnAllowList(address _recipient) public view returns (bool) {\n return\n ATTESTATION_STATION\n .attestations(ATTESTOR, _recipient, bytes32(\"optimist.can-mint\"))\n .length > 0;\n }\n\n /**\n * @notice Returns the token ID for the token owned by a given address. This is the uint256\n * representation of the given address.\n *\n * @return Token ID for the token owned by the given address.\n */\n function tokenIdOfAddress(address _owner) public pure returns (uint256) {\n return uint256(uint160(_owner));\n }\n\n /**\n * @notice Disabled for the Optimist NFT (Soul Bound Token).\n */\n function approve(address, uint256) public pure override {\n revert(\"Optimist: soul bound token\");\n }\n\n /**\n * @notice Disabled for the Optimist NFT (Soul Bound Token).\n */\n function setApprovalForAll(address, bool) public virtual override {\n revert(\"Optimist: soul bound token\");\n }\n\n /**\n * @notice Prevents transfers of the Optimist NFT (Soul Bound Token).\n *\n * @param _from Address of the token sender.\n * @param _to Address of the token recipient.\n */\n function _beforeTokenTransfer(\n address _from,\n address _to,\n uint256\n ) internal virtual override {\n require(_from == address(0) || _to == address(0), \"Optimist: soul bound token\");\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/ERC721BurnableUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/extensions/ERC721Burnable.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../ERC721Upgradeable.sol\";\nimport \"../../../utils/ContextUpgradeable.sol\";\nimport \"../../../proxy/utils/Initializable.sol\";\n\n/**\n * @title ERC721 Burnable Token\n * @dev ERC721 Token that can be burned (destroyed).\n */\nabstract contract ERC721BurnableUpgradeable is Initializable, ContextUpgradeable, ERC721Upgradeable {\n function __ERC721Burnable_init() internal onlyInitializing {\n }\n\n function __ERC721Burnable_init_unchained() internal onlyInitializing {\n }\n /**\n * @dev Burns `tokenId`. See {ERC721-_burn}.\n *\n * Requirements:\n *\n * - The caller must own `tokenId` or be an approved operator.\n */\n function burn(uint256 tokenId) public virtual {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner nor approved\");\n _burn(tokenId);\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n"
},
"@openzeppelin/contracts-upgradeable/token/ERC721/ERC721Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/ERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC721Upgradeable.sol\";\nimport \"./IERC721ReceiverUpgradeable.sol\";\nimport \"./extensions/IERC721MetadataUpgradeable.sol\";\nimport \"../../utils/AddressUpgradeable.sol\";\nimport \"../../utils/ContextUpgradeable.sol\";\nimport \"../../utils/StringsUpgradeable.sol\";\nimport \"../../utils/introspection/ERC165Upgradeable.sol\";\nimport \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including\n * the Metadata extension, but not including the Enumerable extension, which is available separately as\n * {ERC721Enumerable}.\n */\ncontract ERC721Upgradeable is Initializable, ContextUpgradeable, ERC165Upgradeable, IERC721Upgradeable, IERC721MetadataUpgradeable {\n using AddressUpgradeable for address;\n using StringsUpgradeable for uint256;\n\n // Token name\n string private _name;\n\n // Token symbol\n string private _symbol;\n\n // Mapping from token ID to owner address\n mapping(uint256 => address) private _owners;\n\n // Mapping owner address to token count\n mapping(address => uint256) private _balances;\n\n // Mapping from token ID to approved address\n mapping(uint256 => address) private _tokenApprovals;\n\n // Mapping from owner to operator approvals\n mapping(address => mapping(address => bool)) private _operatorApprovals;\n\n /**\n * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.\n */\n function __ERC721_init(string memory name_, string memory symbol_) internal onlyInitializing {\n __ERC721_init_unchained(name_, symbol_);\n }\n\n function __ERC721_init_unchained(string memory name_, string memory symbol_) internal onlyInitializing {\n _name = name_;\n _symbol = symbol_;\n }\n\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165Upgradeable, IERC165Upgradeable) returns (bool) {\n return\n interfaceId == type(IERC721Upgradeable).interfaceId ||\n interfaceId == type(IERC721MetadataUpgradeable).interfaceId ||\n super.supportsInterface(interfaceId);\n }\n\n /**\n * @dev See {IERC721-balanceOf}.\n */\n function balanceOf(address owner) public view virtual override returns (uint256) {\n require(owner != address(0), \"ERC721: address zero is not a valid owner\");\n return _balances[owner];\n }\n\n /**\n * @dev See {IERC721-ownerOf}.\n */\n function ownerOf(uint256 tokenId) public view virtual override returns (address) {\n address owner = _owners[tokenId];\n require(owner != address(0), \"ERC721: invalid token ID\");\n return owner;\n }\n\n /**\n * @dev See {IERC721Metadata-name}.\n */\n function name() public view virtual override returns (string memory) {\n return _name;\n }\n\n /**\n * @dev See {IERC721Metadata-symbol}.\n */\n function symbol() public view virtual override returns (string memory) {\n return _symbol;\n }\n\n /**\n * @dev See {IERC721Metadata-tokenURI}.\n */\n function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {\n _requireMinted(tokenId);\n\n string memory baseURI = _baseURI();\n return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : \"\";\n }\n\n /**\n * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each\n * token will be the concatenation of the `baseURI` and the `tokenId`. Empty\n * by default, can be overridden in child contracts.\n */\n function _baseURI() internal view virtual returns (string memory) {\n return \"\";\n }\n\n /**\n * @dev See {IERC721-approve}.\n */\n function approve(address to, uint256 tokenId) public virtual override {\n address owner = ERC721Upgradeable.ownerOf(tokenId);\n require(to != owner, \"ERC721: approval to current owner\");\n\n require(\n _msgSender() == owner || isApprovedForAll(owner, _msgSender()),\n \"ERC721: approve caller is not token owner nor approved for all\"\n );\n\n _approve(to, tokenId);\n }\n\n /**\n * @dev See {IERC721-getApproved}.\n */\n function getApproved(uint256 tokenId) public view virtual override returns (address) {\n _requireMinted(tokenId);\n\n return _tokenApprovals[tokenId];\n }\n\n /**\n * @dev See {IERC721-setApprovalForAll}.\n */\n function setApprovalForAll(address operator, bool approved) public virtual override {\n _setApprovalForAll(_msgSender(), operator, approved);\n }\n\n /**\n * @dev See {IERC721-isApprovedForAll}.\n */\n function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {\n return _operatorApprovals[owner][operator];\n }\n\n /**\n * @dev See {IERC721-transferFrom}.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n //solhint-disable-next-line max-line-length\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner nor approved\");\n\n _transfer(from, to, tokenId);\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) public virtual override {\n safeTransferFrom(from, to, tokenId, \"\");\n }\n\n /**\n * @dev See {IERC721-safeTransferFrom}.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) public virtual override {\n require(_isApprovedOrOwner(_msgSender(), tokenId), \"ERC721: caller is not token owner nor approved\");\n _safeTransfer(from, to, tokenId, data);\n }\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * `data` is additional data, it has no specified format and it is sent in call to `to`.\n *\n * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.\n * implement alternative mechanisms to perform token transfer, such as signature-based.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeTransfer(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) internal virtual {\n _transfer(from, to, tokenId);\n require(_checkOnERC721Received(from, to, tokenId, data), \"ERC721: transfer to non ERC721Receiver implementer\");\n }\n\n /**\n * @dev Returns whether `tokenId` exists.\n *\n * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.\n *\n * Tokens start existing when they are minted (`_mint`),\n * and stop existing when they are burned (`_burn`).\n */\n function _exists(uint256 tokenId) internal view virtual returns (bool) {\n return _owners[tokenId] != address(0);\n }\n\n /**\n * @dev Returns whether `spender` is allowed to manage `tokenId`.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {\n address owner = ERC721Upgradeable.ownerOf(tokenId);\n return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);\n }\n\n /**\n * @dev Safely mints `tokenId` and transfers it to `to`.\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function _safeMint(address to, uint256 tokenId) internal virtual {\n _safeMint(to, tokenId, \"\");\n }\n\n /**\n * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is\n * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.\n */\n function _safeMint(\n address to,\n uint256 tokenId,\n bytes memory data\n ) internal virtual {\n _mint(to, tokenId);\n require(\n _checkOnERC721Received(address(0), to, tokenId, data),\n \"ERC721: transfer to non ERC721Receiver implementer\"\n );\n }\n\n /**\n * @dev Mints `tokenId` and transfers it to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible\n *\n * Requirements:\n *\n * - `tokenId` must not exist.\n * - `to` cannot be the zero address.\n *\n * Emits a {Transfer} event.\n */\n function _mint(address to, uint256 tokenId) internal virtual {\n require(to != address(0), \"ERC721: mint to the zero address\");\n require(!_exists(tokenId), \"ERC721: token already minted\");\n\n _beforeTokenTransfer(address(0), to, tokenId);\n\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(address(0), to, tokenId);\n\n _afterTokenTransfer(address(0), to, tokenId);\n }\n\n /**\n * @dev Destroys `tokenId`.\n * The approval is cleared when the token is burned.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n *\n * Emits a {Transfer} event.\n */\n function _burn(uint256 tokenId) internal virtual {\n address owner = ERC721Upgradeable.ownerOf(tokenId);\n\n _beforeTokenTransfer(owner, address(0), tokenId);\n\n // Clear approvals\n _approve(address(0), tokenId);\n\n _balances[owner] -= 1;\n delete _owners[tokenId];\n\n emit Transfer(owner, address(0), tokenId);\n\n _afterTokenTransfer(owner, address(0), tokenId);\n }\n\n /**\n * @dev Transfers `tokenId` from `from` to `to`.\n * As opposed to {transferFrom}, this imposes no restrictions on msg.sender.\n *\n * Requirements:\n *\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n *\n * Emits a {Transfer} event.\n */\n function _transfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {\n require(ERC721Upgradeable.ownerOf(tokenId) == from, \"ERC721: transfer from incorrect owner\");\n require(to != address(0), \"ERC721: transfer to the zero address\");\n\n _beforeTokenTransfer(from, to, tokenId);\n\n // Clear approvals from the previous owner\n _approve(address(0), tokenId);\n\n _balances[from] -= 1;\n _balances[to] += 1;\n _owners[tokenId] = to;\n\n emit Transfer(from, to, tokenId);\n\n _afterTokenTransfer(from, to, tokenId);\n }\n\n /**\n * @dev Approve `to` to operate on `tokenId`\n *\n * Emits an {Approval} event.\n */\n function _approve(address to, uint256 tokenId) internal virtual {\n _tokenApprovals[tokenId] = to;\n emit Approval(ERC721Upgradeable.ownerOf(tokenId), to, tokenId);\n }\n\n /**\n * @dev Approve `operator` to operate on all of `owner` tokens\n *\n * Emits an {ApprovalForAll} event.\n */\n function _setApprovalForAll(\n address owner,\n address operator,\n bool approved\n ) internal virtual {\n require(owner != operator, \"ERC721: approve to caller\");\n _operatorApprovals[owner][operator] = approved;\n emit ApprovalForAll(owner, operator, approved);\n }\n\n /**\n * @dev Reverts if the `tokenId` has not been minted yet.\n */\n function _requireMinted(uint256 tokenId) internal view virtual {\n require(_exists(tokenId), \"ERC721: invalid token ID\");\n }\n\n /**\n * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.\n * The call is not executed if the target address is not a contract.\n *\n * @param from address representing the previous owner of the given token ID\n * @param to target address that will receive the tokens\n * @param tokenId uint256 ID of the token to be transferred\n * @param data bytes optional data to send along with the call\n * @return bool whether the call correctly returned the expected magic value\n */\n function _checkOnERC721Received(\n address from,\n address to,\n uint256 tokenId,\n bytes memory data\n ) private returns (bool) {\n if (to.isContract()) {\n try IERC721ReceiverUpgradeable(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {\n return retval == IERC721ReceiverUpgradeable.onERC721Received.selector;\n } catch (bytes memory reason) {\n if (reason.length == 0) {\n revert(\"ERC721: transfer to non ERC721Receiver implementer\");\n } else {\n /// @solidity memory-safe-assembly\n assembly {\n revert(add(32, reason), mload(reason))\n }\n }\n }\n } else {\n return true;\n }\n }\n\n /**\n * @dev Hook that is called before any token transfer. This includes minting\n * and burning.\n *\n * Calling conditions:\n *\n * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be\n * transferred to `to`.\n * - When `from` is zero, `tokenId` will be minted for `to`.\n * - When `to` is zero, ``from``'s `tokenId` will be burned.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _beforeTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n\n /**\n * @dev Hook that is called after any transfer of tokens. This includes\n * minting and burning.\n *\n * Calling conditions:\n *\n * - when `from` and `to` are both non-zero.\n * - `from` and `to` are never both zero.\n *\n * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].\n */\n function _afterTokenTransfer(\n address from,\n address to,\n uint256 tokenId\n ) internal virtual {}\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[44] private __gap;\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/ContextUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)\n\npragma solidity ^0.8.0;\nimport \"../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Provides information about the current execution context, including the\n * sender of the transaction and its data. While these are generally available\n * via msg.sender and msg.data, they should not be accessed in such a direct\n * manner, since when dealing with meta-transactions the account sending and\n * paying for execution may not be the actual sender (as far as an application\n * is concerned).\n *\n * This contract is only required for intermediate, library-like contracts.\n */\nabstract contract ContextUpgradeable is Initializable {\n function __Context_init() internal onlyInitializing {\n }\n\n function __Context_init_unchained() internal onlyInitializing {\n }\n function _msgSender() internal view virtual returns (address) {\n return msg.sender;\n }\n\n function _msgData() internal view virtual returns (bytes calldata) {\n return msg.data;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n"
},
"@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (proxy/utils/Initializable.sol)\n\npragma solidity ^0.8.2;\n\nimport \"../../utils/AddressUpgradeable.sol\";\n\n/**\n * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed\n * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an\n * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer\n * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.\n *\n * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be\n * reused. This mechanism prevents re-execution of each \"step\" but allows the creation of new initialization steps in\n * case an upgrade adds a module that needs to be initialized.\n *\n * For example:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * contract MyToken is ERC20Upgradeable {\n * function initialize() initializer public {\n * __ERC20_init(\"MyToken\", \"MTK\");\n * }\n * }\n * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {\n * function initializeV2() reinitializer(2) public {\n * __ERC20Permit_init(\"MyToken\");\n * }\n * }\n * ```\n *\n * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as\n * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.\n *\n * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure\n * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.\n *\n * [CAUTION]\n * ====\n * Avoid leaving a contract uninitialized.\n *\n * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation\n * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke\n * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:\n *\n * [.hljs-theme-light.nopadding]\n * ```\n * /// @custom:oz-upgrades-unsafe-allow constructor\n * constructor() {\n * _disableInitializers();\n * }\n * ```\n * ====\n */\nabstract contract Initializable {\n /**\n * @dev Indicates that the contract has been initialized.\n * @custom:oz-retyped-from bool\n */\n uint8 private _initialized;\n\n /**\n * @dev Indicates that the contract is in the process of being initialized.\n */\n bool private _initializing;\n\n /**\n * @dev Triggered when the contract has been initialized or reinitialized.\n */\n event Initialized(uint8 version);\n\n /**\n * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,\n * `onlyInitializing` functions can be used to initialize parent contracts. Equivalent to `reinitializer(1)`.\n */\n modifier initializer() {\n bool isTopLevelCall = !_initializing;\n require(\n (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),\n \"Initializable: contract is already initialized\"\n );\n _initialized = 1;\n if (isTopLevelCall) {\n _initializing = true;\n }\n _;\n if (isTopLevelCall) {\n _initializing = false;\n emit Initialized(1);\n }\n }\n\n /**\n * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the\n * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be\n * used to initialize parent contracts.\n *\n * `initializer` is equivalent to `reinitializer(1)`, so a reinitializer may be used after the original\n * initialization step. This is essential to configure modules that are added through upgrades and that require\n * initialization.\n *\n * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in\n * a contract, executing them in the right order is up to the developer or operator.\n */\n modifier reinitializer(uint8 version) {\n require(!_initializing && _initialized < version, \"Initializable: contract is already initialized\");\n _initialized = version;\n _initializing = true;\n _;\n _initializing = false;\n emit Initialized(version);\n }\n\n /**\n * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the\n * {initializer} and {reinitializer} modifiers, directly or indirectly.\n */\n modifier onlyInitializing() {\n require(_initializing, \"Initializable: contract is not initializing\");\n _;\n }\n\n /**\n * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.\n * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized\n * to any version. It is recommended to use this to lock implementation contracts that are designed to be called\n * through proxies.\n */\n function _disableInitializers() internal virtual {\n require(!_initializing, \"Initializable: contract is initializing\");\n if (_initialized < type(uint8).max) {\n _initialized = type(uint8).max;\n emit Initialized(type(uint8).max);\n }\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../../utils/introspection/IERC165Upgradeable.sol\";\n\n/**\n * @dev Required interface of an ERC721 compliant contract.\n */\ninterface IERC721Upgradeable is IERC165Upgradeable {\n /**\n * @dev Emitted when `tokenId` token is transferred from `from` to `to`.\n */\n event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.\n */\n event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);\n\n /**\n * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.\n */\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /**\n * @dev Returns the number of tokens in ``owner``'s account.\n */\n function balanceOf(address owner) external view returns (uint256 balance);\n\n /**\n * @dev Returns the owner of the `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function ownerOf(uint256 tokenId) external view returns (address owner);\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId,\n bytes calldata data\n ) external;\n\n /**\n * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients\n * are aware of the ERC721 protocol to prevent tokens from being forever locked.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must exist and be owned by `from`.\n * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.\n * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.\n *\n * Emits a {Transfer} event.\n */\n function safeTransferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Transfers `tokenId` token from `from` to `to`.\n *\n * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.\n *\n * Requirements:\n *\n * - `from` cannot be the zero address.\n * - `to` cannot be the zero address.\n * - `tokenId` token must be owned by `from`.\n * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.\n *\n * Emits a {Transfer} event.\n */\n function transferFrom(\n address from,\n address to,\n uint256 tokenId\n ) external;\n\n /**\n * @dev Gives permission to `to` to transfer `tokenId` token to another account.\n * The approval is cleared when the token is transferred.\n *\n * Only a single account can be approved at a time, so approving the zero address clears previous approvals.\n *\n * Requirements:\n *\n * - The caller must own the token or be an approved operator.\n * - `tokenId` must exist.\n *\n * Emits an {Approval} event.\n */\n function approve(address to, uint256 tokenId) external;\n\n /**\n * @dev Approve or remove `operator` as an operator for the caller.\n * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.\n *\n * Requirements:\n *\n * - The `operator` cannot be the caller.\n *\n * Emits an {ApprovalForAll} event.\n */\n function setApprovalForAll(address operator, bool _approved) external;\n\n /**\n * @dev Returns the account approved for `tokenId` token.\n *\n * Requirements:\n *\n * - `tokenId` must exist.\n */\n function getApproved(uint256 tokenId) external view returns (address operator);\n\n /**\n * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.\n *\n * See {setApprovalForAll}\n */\n function isApprovedForAll(address owner, address operator) external view returns (bool);\n}\n"
},
"@openzeppelin/contracts-upgradeable/token/ERC721/IERC721ReceiverUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @title ERC721 token receiver interface\n * @dev Interface for any contract that wants to support safeTransfers\n * from ERC721 asset contracts.\n */\ninterface IERC721ReceiverUpgradeable {\n /**\n * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}\n * by `operator` from `from`, this function is called.\n *\n * It must return its Solidity selector to confirm the token transfer.\n * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.\n *\n * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.\n */\n function onERC721Received(\n address operator,\n address from,\n uint256 tokenId,\n bytes calldata data\n ) external returns (bytes4);\n}\n"
},
"@openzeppelin/contracts-upgradeable/token/ERC721/extensions/IERC721MetadataUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)\n\npragma solidity ^0.8.0;\n\nimport \"../IERC721Upgradeable.sol\";\n\n/**\n * @title ERC-721 Non-Fungible Token Standard, optional metadata extension\n * @dev See https://eips.ethereum.org/EIPS/eip-721\n */\ninterface IERC721MetadataUpgradeable is IERC721Upgradeable {\n /**\n * @dev Returns the token collection name.\n */\n function name() external view returns (string memory);\n\n /**\n * @dev Returns the token collection symbol.\n */\n function symbol() external view returns (string memory);\n\n /**\n * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.\n */\n function tokenURI(uint256 tokenId) external view returns (string memory);\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/AddressUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)\n\npragma solidity ^0.8.1;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary AddressUpgradeable {\n /**\n * @dev Returns true if `account` is a contract.\n *\n * [IMPORTANT]\n * ====\n * It is unsafe to assume that an address for which this function returns\n * false is an externally-owned account (EOA) and not a contract.\n *\n * Among others, `isContract` will return false for the following\n * types of addresses:\n *\n * - an externally-owned account\n * - a contract in construction\n * - an address where a contract will be created\n * - an address where a contract lived, but was destroyed\n * ====\n *\n * [IMPORTANT]\n * ====\n * You shouldn't rely on `isContract` to protect against flash loan attacks!\n *\n * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets\n * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract\n * constructor.\n * ====\n */\n function isContract(address account) internal view returns (bool) {\n // This method relies on extcodesize/address.code.length, which returns 0\n // for contracts in construction, since the code is only stored at the end\n // of the constructor execution.\n\n return account.code.length > 0;\n }\n\n /**\n * @dev Replacement for Solidity's `transfer`: sends `amount` wei to\n * `recipient`, forwarding all available gas and reverting on errors.\n *\n * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n * of certain opcodes, possibly making contracts go over the 2300 gas limit\n * imposed by `transfer`, making them unable to receive funds via\n * `transfer`. {sendValue} removes this limitation.\n *\n * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n *\n * IMPORTANT: because control is transferred to `recipient`, care must be\n * taken to not create reentrancy vulnerabilities. Consider using\n * {ReentrancyGuard} or the\n * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n */\n function sendValue(address payable recipient, uint256 amount) internal {\n require(address(this).balance >= amount, \"Address: insufficient balance\");\n\n (bool success, ) = recipient.call{value: amount}(\"\");\n require(success, \"Address: unable to send value, recipient may have reverted\");\n }\n\n /**\n * @dev Performs a Solidity function call using a low level `call`. A\n * plain `call` is an unsafe replacement for a function call: use this\n * function instead.\n *\n * If `target` reverts with a revert reason, it is bubbled up by this\n * function (like regular Solidity function calls).\n *\n * Returns the raw returned data. To convert to the expected return value,\n * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].\n *\n * Requirements:\n *\n * - `target` must be a contract.\n * - calling `target` with `data` must not revert.\n *\n * _Available since v3.1._\n */\n function functionCall(address target, bytes memory data) internal returns (bytes memory) {\n return functionCall(target, data, \"Address: low-level call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with\n * `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, 0, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but also transferring `value` wei to `target`.\n *\n * Requirements:\n *\n * - the calling contract must have an ETH balance of at least `value`.\n * - the called Solidity function must be `payable`.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value\n ) internal returns (bytes memory) {\n return functionCallWithValue(target, data, value, \"Address: low-level call with value failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but\n * with `errorMessage` as a fallback revert reason when `target` reverts.\n *\n * _Available since v3.1._\n */\n function functionCallWithValue(\n address target,\n bytes memory data,\n uint256 value,\n string memory errorMessage\n ) internal returns (bytes memory) {\n require(address(this).balance >= value, \"Address: insufficient balance for call\");\n require(isContract(target), \"Address: call to non-contract\");\n\n (bool success, bytes memory returndata) = target.call{value: value}(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {\n return functionStaticCall(target, data, \"Address: low-level static call failed\");\n }\n\n /**\n * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],\n * but performing a static call.\n *\n * _Available since v3.3._\n */\n function functionStaticCall(\n address target,\n bytes memory data,\n string memory errorMessage\n ) internal view returns (bytes memory) {\n require(isContract(target), \"Address: static call to non-contract\");\n\n (bool success, bytes memory returndata) = target.staticcall(data);\n return verifyCallResult(success, returndata, errorMessage);\n }\n\n /**\n * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the\n * revert reason using the provided one.\n *\n * _Available since v4.3._\n */\n function verifyCallResult(\n bool success,\n bytes memory returndata,\n string memory errorMessage\n ) internal pure returns (bytes memory) {\n if (success) {\n return returndata;\n } else {\n // Look for revert reason and bubble it up if present\n if (returndata.length > 0) {\n // The easiest way to bubble the revert reason is using memory via assembly\n /// @solidity memory-safe-assembly\n assembly {\n let returndata_size := mload(returndata)\n revert(add(32, returndata), returndata_size)\n }\n } else {\n revert(errorMessage);\n }\n }\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/StringsUpgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev String operations.\n */\nlibrary StringsUpgradeable {\n bytes16 private constant _HEX_SYMBOLS = \"0123456789abcdef\";\n uint8 private constant _ADDRESS_LENGTH = 20;\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` decimal representation.\n */\n function toString(uint256 value) internal pure returns (string memory) {\n // Inspired by OraclizeAPI's implementation - MIT licence\n // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol\n\n if (value == 0) {\n return \"0\";\n }\n uint256 temp = value;\n uint256 digits;\n while (temp != 0) {\n digits++;\n temp /= 10;\n }\n bytes memory buffer = new bytes(digits);\n while (value != 0) {\n digits -= 1;\n buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));\n value /= 10;\n }\n return string(buffer);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.\n */\n function toHexString(uint256 value) internal pure returns (string memory) {\n if (value == 0) {\n return \"0x00\";\n }\n uint256 temp = value;\n uint256 length = 0;\n while (temp != 0) {\n length++;\n temp >>= 8;\n }\n return toHexString(value, length);\n }\n\n /**\n * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.\n */\n function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {\n bytes memory buffer = new bytes(2 * length + 2);\n buffer[0] = \"0\";\n buffer[1] = \"x\";\n for (uint256 i = 2 * length + 1; i > 1; --i) {\n buffer[i] = _HEX_SYMBOLS[value & 0xf];\n value >>= 4;\n }\n require(value == 0, \"Strings: hex length insufficient\");\n return string(buffer);\n }\n\n /**\n * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.\n */\n function toHexString(address addr) internal pure returns (string memory) {\n return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);\n }\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/introspection/ERC165Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)\n\npragma solidity ^0.8.0;\n\nimport \"./IERC165Upgradeable.sol\";\nimport \"../../proxy/utils/Initializable.sol\";\n\n/**\n * @dev Implementation of the {IERC165} interface.\n *\n * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check\n * for the additional interface id that will be supported. For example:\n *\n * ```solidity\n * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);\n * }\n * ```\n *\n * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.\n */\nabstract contract ERC165Upgradeable is Initializable, IERC165Upgradeable {\n function __ERC165_init() internal onlyInitializing {\n }\n\n function __ERC165_init_unchained() internal onlyInitializing {\n }\n /**\n * @dev See {IERC165-supportsInterface}.\n */\n function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {\n return interfaceId == type(IERC165Upgradeable).interfaceId;\n }\n\n /**\n * @dev This empty reserved space is put in place to allow future versions to add new\n * variables without shifting down storage in the inheritance chain.\n * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps\n */\n uint256[50] private __gap;\n}\n"
},
"@openzeppelin/contracts-upgradeable/utils/introspection/IERC165Upgradeable.sol": {
"content": "// SPDX-License-Identifier: MIT\n// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)\n\npragma solidity ^0.8.0;\n\n/**\n * @dev Interface of the ERC165 standard, as defined in the\n * https://eips.ethereum.org/EIPS/eip-165[EIP].\n *\n * Implementers can declare support of contract interfaces, which can then be\n * queried by others ({ERC165Checker}).\n *\n * For an implementation, see {ERC165}.\n */\ninterface IERC165Upgradeable {\n /**\n * @dev Returns true if this contract implements the interface defined by\n * `interfaceId`. See the corresponding\n * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]\n * to learn more about how these ids are created.\n *\n * This function call must use less than 30 000 gas.\n */\n function supportsInterface(bytes4 interfaceId) external view returns (bool);\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
{
"language": "Solidity",
"sources": {
"contracts/universal/AssetReceiver.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\nimport { Transactor } from \"./Transactor.sol\";\n\n/**\n * @title AssetReceiver\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\n */\ncontract AssetReceiver is Transactor {\n /**\n * Emitted when ETH is received by this address.\n */\n event ReceivedETH(address indexed from, uint256 amount);\n\n /**\n * Emitted when ETH is withdrawn from this address.\n */\n event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\n\n /**\n * Emitted when ERC20 tokens are withdrawn from this address.\n */\n event WithdrewERC20(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 amount\n );\n\n /**\n * Emitted when ERC721 tokens are withdrawn from this address.\n */\n event WithdrewERC721(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 id\n );\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Transactor(_owner) {}\n\n /**\n * Make sure we can receive ETH.\n */\n receive() external payable {\n emit ReceivedETH(msg.sender, msg.value);\n }\n\n /**\n * Withdraws full ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n */\n function withdrawETH(address payable _to) external onlyOwner {\n withdrawETH(_to, address(this).balance);\n }\n\n /**\n * Withdraws partial ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n * @param _amount Amount of ETH to withdraw.\n */\n function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\n // slither-disable-next-line reentrancy-unlimited-gas\n _to.transfer(_amount);\n emit WithdrewETH(msg.sender, _to, _amount);\n }\n\n /**\n * Withdraws full ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n */\n function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\n withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\n }\n\n /**\n * Withdraws partial ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n * @param _amount Amount of ERC20 to withdraw.\n */\n function withdrawERC20(\n ERC20 _asset,\n address _to,\n uint256 _amount\n ) public onlyOwner {\n // slither-disable-next-line unchecked-transfer\n _asset.transfer(_to, _amount);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\n }\n\n /**\n * Withdraws ERC721 token to the recipient.\n *\n * @param _asset ERC721 token to withdraw.\n * @param _to Address to receive the ERC721 token.\n * @param _id Token ID of the ERC721 token to withdraw.\n */\n function withdrawERC721(\n ERC721 _asset,\n address _to,\n uint256 _id\n ) external onlyOwner {\n _asset.transferFrom(address(this), _to, _id);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC20.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n uint8 public immutable decimals;\n\n /*//////////////////////////////////////////////////////////////\n ERC20 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 public totalSupply;\n\n mapping(address => uint256) public balanceOf;\n\n mapping(address => mapping(address => uint256)) public allowance;\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal immutable INITIAL_CHAIN_ID;\n\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n mapping(address => uint256) public nonces;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals\n ) {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n INITIAL_CHAIN_ID = block.chainid;\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 amount) public virtual returns (bool) {\n allowance[msg.sender][spender] = amount;\n\n emit Approval(msg.sender, spender, amount);\n\n return true;\n }\n\n function transfer(address to, uint256 amount) public virtual returns (bool) {\n balanceOf[msg.sender] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(msg.sender, to, amount);\n\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual returns (bool) {\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n balanceOf[from] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual {\n require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n // Unchecked because the only math done is incrementing\n // the owner's nonce which cannot realistically overflow.\n unchecked {\n address recoveredAddress = ecrecover(\n keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(\n abi.encode(\n keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n ),\n owner,\n spender,\n value,\n nonces[owner]++,\n deadline\n )\n )\n )\n ),\n v,\n r,\n s\n );\n\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n allowance[recoveredAddress][spender] = value;\n }\n\n emit Approval(owner, spender, value);\n }\n\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n }\n\n function computeDomainSeparator() internal view virtual returns (bytes32) {\n return\n keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(name)),\n keccak256(\"1\"),\n block.chainid,\n address(this)\n )\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 amount) internal virtual {\n totalSupply += amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal virtual {\n balanceOf[from] -= amount;\n\n // Cannot underflow because a user's balance\n // will never be larger than the total supply.\n unchecked {\n totalSupply -= amount;\n }\n\n emit Transfer(from, address(0), amount);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC721.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity >=0.8.0;\n\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) internal _ownerOf;\n\n mapping(address => uint256) internal _balanceOf;\n\n function ownerOf(uint256 id) public view virtual returns (address owner) {\n require((owner = _ownerOf[id]) != address(0), \"NOT_MINTED\");\n }\n\n function balanceOf(address owner) public view virtual returns (uint256) {\n require(owner != address(0), \"ZERO_ADDRESS\");\n\n return _balanceOf[owner];\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) public getApproved;\n\n mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 id) public virtual {\n address owner = _ownerOf[id];\n\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n getApproved[id] = spender;\n\n emit Approval(owner, spender, id);\n }\n\n function setApprovalForAll(address operator, bool approved) public virtual {\n isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n require(from == _ownerOf[id], \"WRONG_FROM\");\n\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(\n msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\n \"NOT_AUTHORIZED\"\n );\n\n // Underflow of the sender's balance is impossible because we check for\n // ownership above and the recipient's balance can't realistically overflow.\n unchecked {\n _balanceOf[from]--;\n\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n delete getApproved[id];\n\n emit Transfer(from, to, id);\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n bytes calldata data\n ) public virtual {\n transferFrom(from, to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 id) internal virtual {\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(_ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n // Counter overflow is incredibly unrealistic.\n unchecked {\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n emit Transfer(address(0), to, id);\n }\n\n function _burn(uint256 id) internal virtual {\n address owner = _ownerOf[id];\n\n require(owner != address(0), \"NOT_MINTED\");\n\n // Ownership check above ensures no underflow.\n unchecked {\n _balanceOf[owner]--;\n }\n\n delete _ownerOf[id];\n\n delete getApproved[id];\n\n emit Transfer(owner, address(0), id);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL SAFE MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _safeMint(address to, uint256 id) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _safeMint(\n address to,\n uint256 id,\n bytes memory data\n ) internal virtual {\n _mint(to, id);\n\n if (to.code.length != 0)\n require(\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721TokenReceiver {\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external virtual returns (bytes4) {\n return ERC721TokenReceiver.onERC721Received.selector;\n }\n}\n"
},
"contracts/universal/Transactor.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { Owned } from \"@rari-capital/solmate/src/auth/Owned.sol\";\n\n/**\n * @title Transactor\n * @notice Transactor is a minimal contract that can send transactions.\n */\ncontract Transactor is Owned {\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Owned(_owner) {}\n\n /**\n * Sends a CALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @param _value ETH value to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function CALL(\n address _target,\n bytes memory _data,\n uint256 _gas,\n uint256 _value\n ) external payable onlyOwner returns (bool, bytes memory) {\n return _target.call{ gas: _gas, value: _value }(_data);\n }\n\n /**\n * Sends a DELEGATECALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function DELEGATECALL(\n address _target,\n bytes memory _data,\n uint256 _gas\n ) external payable onlyOwner returns (bool, bytes memory) {\n // slither-disable-next-line controlled-delegatecall\n return _target.delegatecall{ gas: _gas }(_data);\n }\n}\n"
},
"@rari-capital/solmate/src/auth/Owned.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event OwnerUpdated(address indexed user, address indexed newOwner);\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP STORAGE\n //////////////////////////////////////////////////////////////*/\n\n address public owner;\n\n modifier onlyOwner() virtual {\n require(msg.sender == owner, \"UNAUTHORIZED\");\n\n _;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address _owner) {\n owner = _owner;\n\n emit OwnerUpdated(address(0), _owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function setOwner(address newOwner) public virtual onlyOwner {\n owner = newOwner;\n\n emit OwnerUpdated(msg.sender, newOwner);\n }\n}\n"
},
"contracts/universal/drippie/Drippie.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { AssetReceiver } from \"../AssetReceiver.sol\";\nimport { IDripCheck } from \"./IDripCheck.sol\";\n\n/**\n * @title Drippie\n * @notice Drippie is a system for managing automated contract interactions. A specific interaction\n * is called a \"drip\" and can be executed according to some condition (called a dripcheck) and an\n * execution interval. Drips cannot be executed faster than the execution interval. Drips can\n * trigger arbitrary contract calls where the calling contract is this contract address. Drips can\n * also send ETH value, which makes them ideal for keeping addresses sufficiently funded with ETH.\n * Drippie is designed to be connected with smart contract automation services so that drips can be\n * executed automatically. However, Drippie is specifically designed to be separated from these\n * services so that trust assumptions are better compartmentalized.\n */\ncontract Drippie is AssetReceiver {\n /**\n * Enum representing different status options for a given drip.\n */\n enum DripStatus {\n NONE,\n ACTIVE,\n PAUSED,\n ARCHIVED\n }\n\n /**\n * Represents a drip action.\n */\n struct DripAction {\n address payable target;\n bytes data;\n uint256 value;\n }\n\n /**\n * Represents the configuration for a given drip.\n */\n struct DripConfig {\n uint256 interval;\n IDripCheck dripcheck;\n bytes checkparams;\n DripAction[] actions;\n }\n\n /**\n * Represents the state of an active drip.\n */\n struct DripState {\n DripStatus status;\n DripConfig config;\n uint256 last;\n }\n\n /**\n * Emitted when a new drip is created.\n */\n event DripCreated(string indexed name, DripConfig config);\n\n /**\n * Emitted when a drip status is updated.\n */\n event DripStatusUpdated(string indexed name, DripStatus status);\n\n /**\n * Emitted when a drip is executed.\n */\n event DripExecuted(string indexed name, address indexed executor, uint256 timestamp);\n\n /**\n * Maps from drip names to drip states.\n */\n mapping(string => DripState) public drips;\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) AssetReceiver(_owner) {}\n\n /**\n * Creates a new drip with the given name and configuration. Once created, drips cannot be\n * modified in any way (this is a security measure). If you want to update a drip, simply pause\n * (and potentially archive) the existing drip and create a new one.\n *\n * @param _name Name of the drip.\n * @param _config Configuration for the drip.\n */\n function create(string memory _name, DripConfig memory _config) external onlyOwner {\n // Make sure this drip doesn't already exist. We *must* guarantee that no other function\n // will ever set the status of a drip back to NONE after it's been created. This is why\n // archival is a separate status.\n require(\n drips[_name].status == DripStatus.NONE,\n \"Drippie: drip with that name already exists\"\n );\n\n // We initialize this way because Solidity won't let us copy arrays into storage yet.\n DripState storage state = drips[_name];\n state.status = DripStatus.PAUSED;\n state.config.interval = _config.interval;\n state.config.dripcheck = _config.dripcheck;\n state.config.checkparams = _config.checkparams;\n\n // Solidity doesn't let us copy arrays into storage, so we push each array one by one.\n for (uint256 i = 0; i < _config.actions.length; i++) {\n state.config.actions.push(_config.actions[i]);\n }\n\n // Tell the world!\n emit DripCreated(_name, _config);\n }\n\n /**\n * Sets the status for a given drip. The behavior of this function depends on the status that\n * the user is trying to set. A drip can always move between ACTIVE and PAUSED, but it can\n * never move back to NONE and once ARCHIVED, it can never move back to ACTIVE or PAUSED.\n *\n * @param _name Name of the drip to update.\n * @param _status New drip status.\n */\n function status(string memory _name, DripStatus _status) external onlyOwner {\n // Make sure we can never set drip status back to NONE. A simple security measure to\n // prevent accidental overwrites if this code is ever updated down the line.\n require(\n _status != DripStatus.NONE,\n \"Drippie: drip status can never be set back to NONE after creation\"\n );\n\n // Make sure the drip in question actually exists. Not strictly necessary but there doesn't\n // seem to be any clear reason why you would want to do this, and it may save some gas in\n // the case of a front-end bug.\n require(\n drips[_name].status != DripStatus.NONE,\n \"Drippie: drip with that name does not exist\"\n );\n\n // Once a drip has been archived, it cannot be un-archived. This is, after all, the entire\n // point of archiving a drip.\n require(\n drips[_name].status != DripStatus.ARCHIVED,\n \"Drippie: drip with that name has been archived\"\n );\n\n // Although not strictly necessary, we make sure that the status here is actually changing.\n // This may save the client some gas if there's a front-end bug and the user accidentally\n // tries to \"change\" the status to the same value as before.\n require(\n drips[_name].status != _status,\n \"Drippie: cannot set drip status to same status as before\"\n );\n\n // If the user is trying to archive this drip, make sure the drip has been paused. We do\n // not allow users to archive active drips so that the effects of this action are more\n // abundantly clear.\n if (_status == DripStatus.ARCHIVED) {\n require(\n drips[_name].status == DripStatus.PAUSED,\n \"Drippie: drip must be paused to be archived\"\n );\n }\n\n // If we made it here then we can safely update the status.\n drips[_name].status = _status;\n emit DripStatusUpdated(_name, drips[_name].status);\n }\n\n /**\n * Triggers a drip. This function is deliberately left as a public function because the\n * assumption being made here is that setting the drip to ACTIVE is an affirmative signal that\n * the drip should be executable according to the drip parameters, drip check, and drip\n * interval. Note that drip parameters are read entirely from the state and are not supplied as\n * user input, so there should not be any way for a non-authorized user to influence the\n * behavior of the drip.\n *\n * @param _name Name of the drip to trigger.\n */\n function drip(string memory _name) external {\n DripState storage state = drips[_name];\n\n // Only allow active drips to be executed, an obvious security measure.\n require(\n state.status == DripStatus.ACTIVE,\n \"Drippie: selected drip does not exist or is not currently active\"\n );\n\n // Don't drip if the drip interval has not yet elapsed since the last time we dripped. This\n // is a safety measure that prevents a malicious recipient from, e.g., spending all of\n // their funds and repeatedly requesting new drips. Limits the potential impact of a\n // compromised recipient to just a single drip interval, after which the drip can be paused\n // by the owner address.\n require(\n state.last + state.config.interval <= block.timestamp,\n \"Drippie: drip interval has not elapsed since last drip\"\n );\n\n // Make sure we're allowed to execute this drip.\n require(\n state.config.dripcheck.check(state.config.checkparams),\n \"Drippie: dripcheck failed so drip is not yet ready to be triggered\"\n );\n\n // Update the last execution time for this drip before the call. Note that it's entirely\n // possible for a drip to be executed multiple times per block or even multiple times\n // within the same transaction (via re-entrancy) if the drip interval is set to zero. Users\n // should set a drip interval of 1 if they'd like the drip to be executed only once per\n // block (since this will then prevent re-entrancy).\n state.last = block.timestamp;\n\n // Execute each action in the drip. We allow drips to have multiple actions because there\n // are scenarios in which a contract must do multiple things atomically. For example, the\n // contract may need to withdraw ETH from one account and then deposit that ETH into\n // another account within the same transaction.\n uint256 len = state.config.actions.length;\n for (uint256 i = 0; i < len; i++) {\n // Must be marked as \"storage\" because copying structs into memory is not yet supported\n // by Solidity. Won't significantly reduce gas costs but at least makes it easier to\n // read what the rest of this section is doing.\n DripAction storage action = state.config.actions[i];\n\n // Actually execute the action. We could use ExcessivelySafeCall here but not strictly\n // necessary (worst case, a drip gets bricked IFF the target is malicious, doubt this\n // will ever happen in practice). Could save a marginal amount of gas to ignore the\n // returndata.\n // slither-disable-next-line calls-loop\n (bool success, ) = action.target.call{ value: action.value }(action.data);\n\n // Generally should not happen, but could if there's a misconfiguration (e.g., passing\n // the wrong data to the target contract), the recipient is not payable, or\n // insufficient gas was supplied to this transaction. We revert so the drip can be\n // fixed and triggered again later. Means we cannot emit an event to alert of the\n // failure, but can reasonably be detected by off-chain services even without an event.\n // Note that this forces the drip executor to supply sufficient gas to the call\n // (assuming there is some sufficient gas limit that exists, otherwise the drip will\n // not execute).\n require(\n success,\n \"Drippie: drip was unsuccessful, please check your configuration for mistakes\"\n );\n }\n\n emit DripExecuted(_name, msg.sender, block.timestamp);\n }\n}\n"
},
"contracts/universal/drippie/IDripCheck.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ninterface IDripCheck {\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\n // possible to easily encode parameters on the client side. Solidity does not support generics\n // so it's not possible to do this with explicit typing.\n\n function check(bytes memory _params) external view returns (bool);\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckTrue.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckTrue\n * @notice DripCheck that always returns true.\n */\ncontract CheckTrue is IDripCheck {\n function check(bytes memory) external pure returns (bool) {\n return true;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\ninterface IGelatoTreasury {\n function userTokenBalance(address _user, address _token) external view returns (uint256);\n}\n\n/**\n * @title CheckGelatoLow\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\n */\ncontract CheckGelatoLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address treasury;\n uint256 threshold;\n address recipient;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check GelatoTreasury ETH balance is below threshold.\n return\n IGelatoTreasury(params.treasury).userTokenBalance(\n params.recipient,\n // Gelato represents ETH as 0xeeeee....eeeee\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\n ) < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceLow\n * @notice DripCheck for checking if an account's balance is below a given threshold.\n */\ncontract CheckBalanceLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target ETH balance is below threshold.\n return params.target.balance < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceHigh\n * @notice DripCheck for checking if an account's balance is above a given threshold.\n */\ncontract CheckBalanceHigh is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target balance is above threshold.\n return params.target.balance > params.threshold;\n }\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
\ No newline at end of file
{
"language": "Solidity",
"sources": {
"contracts/universal/AssetReceiver.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { ERC20 } from \"@rari-capital/solmate/src/tokens/ERC20.sol\";\nimport { ERC721 } from \"@rari-capital/solmate/src/tokens/ERC721.sol\";\nimport { Transactor } from \"./Transactor.sol\";\n\n/**\n * @title AssetReceiver\n * @notice AssetReceiver is a minimal contract for receiving funds assets in the form of either\n * ETH, ERC20 tokens, or ERC721 tokens. Only the contract owner may withdraw the assets.\n */\ncontract AssetReceiver is Transactor {\n /**\n * Emitted when ETH is received by this address.\n */\n event ReceivedETH(address indexed from, uint256 amount);\n\n /**\n * Emitted when ETH is withdrawn from this address.\n */\n event WithdrewETH(address indexed withdrawer, address indexed recipient, uint256 amount);\n\n /**\n * Emitted when ERC20 tokens are withdrawn from this address.\n */\n event WithdrewERC20(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 amount\n );\n\n /**\n * Emitted when ERC721 tokens are withdrawn from this address.\n */\n event WithdrewERC721(\n address indexed withdrawer,\n address indexed recipient,\n address indexed asset,\n uint256 id\n );\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Transactor(_owner) {}\n\n /**\n * Make sure we can receive ETH.\n */\n receive() external payable {\n emit ReceivedETH(msg.sender, msg.value);\n }\n\n /**\n * Withdraws full ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n */\n function withdrawETH(address payable _to) external onlyOwner {\n withdrawETH(_to, address(this).balance);\n }\n\n /**\n * Withdraws partial ETH balance to the recipient.\n *\n * @param _to Address to receive the ETH balance.\n * @param _amount Amount of ETH to withdraw.\n */\n function withdrawETH(address payable _to, uint256 _amount) public onlyOwner {\n // slither-disable-next-line reentrancy-unlimited-gas\n _to.transfer(_amount);\n emit WithdrewETH(msg.sender, _to, _amount);\n }\n\n /**\n * Withdraws full ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n */\n function withdrawERC20(ERC20 _asset, address _to) external onlyOwner {\n withdrawERC20(_asset, _to, _asset.balanceOf(address(this)));\n }\n\n /**\n * Withdraws partial ERC20 balance to the recipient.\n *\n * @param _asset ERC20 token to withdraw.\n * @param _to Address to receive the ERC20 balance.\n * @param _amount Amount of ERC20 to withdraw.\n */\n function withdrawERC20(\n ERC20 _asset,\n address _to,\n uint256 _amount\n ) public onlyOwner {\n // slither-disable-next-line unchecked-transfer\n _asset.transfer(_to, _amount);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC20(msg.sender, _to, address(_asset), _amount);\n }\n\n /**\n * Withdraws ERC721 token to the recipient.\n *\n * @param _asset ERC721 token to withdraw.\n * @param _to Address to receive the ERC721 token.\n * @param _id Token ID of the ERC721 token to withdraw.\n */\n function withdrawERC721(\n ERC721 _asset,\n address _to,\n uint256 _id\n ) external onlyOwner {\n _asset.transferFrom(address(this), _to, _id);\n // slither-disable-next-line reentrancy-events\n emit WithdrewERC721(msg.sender, _to, address(_asset), _id);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC20.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Modern and gas efficient ERC20 + EIP-2612 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol)\n/// @author Modified from Uniswap (https://github.com/Uniswap/uniswap-v2-core/blob/master/contracts/UniswapV2ERC20.sol)\n/// @dev Do not manually set balances without updating totalSupply, as the sum of all user balances must not exceed it.\nabstract contract ERC20 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 amount);\n\n event Approval(address indexed owner, address indexed spender, uint256 amount);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n uint8 public immutable decimals;\n\n /*//////////////////////////////////////////////////////////////\n ERC20 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 public totalSupply;\n\n mapping(address => uint256) public balanceOf;\n\n mapping(address => mapping(address => uint256)) public allowance;\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 STORAGE\n //////////////////////////////////////////////////////////////*/\n\n uint256 internal immutable INITIAL_CHAIN_ID;\n\n bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;\n\n mapping(address => uint256) public nonces;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(\n string memory _name,\n string memory _symbol,\n uint8 _decimals\n ) {\n name = _name;\n symbol = _symbol;\n decimals = _decimals;\n\n INITIAL_CHAIN_ID = block.chainid;\n INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC20 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 amount) public virtual returns (bool) {\n allowance[msg.sender][spender] = amount;\n\n emit Approval(msg.sender, spender, amount);\n\n return true;\n }\n\n function transfer(address to, uint256 amount) public virtual returns (bool) {\n balanceOf[msg.sender] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(msg.sender, to, amount);\n\n return true;\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 amount\n ) public virtual returns (bool) {\n uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.\n\n if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;\n\n balanceOf[from] -= amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(from, to, amount);\n\n return true;\n }\n\n /*//////////////////////////////////////////////////////////////\n EIP-2612 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function permit(\n address owner,\n address spender,\n uint256 value,\n uint256 deadline,\n uint8 v,\n bytes32 r,\n bytes32 s\n ) public virtual {\n require(deadline >= block.timestamp, \"PERMIT_DEADLINE_EXPIRED\");\n\n // Unchecked because the only math done is incrementing\n // the owner's nonce which cannot realistically overflow.\n unchecked {\n address recoveredAddress = ecrecover(\n keccak256(\n abi.encodePacked(\n \"\\x19\\x01\",\n DOMAIN_SEPARATOR(),\n keccak256(\n abi.encode(\n keccak256(\n \"Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)\"\n ),\n owner,\n spender,\n value,\n nonces[owner]++,\n deadline\n )\n )\n )\n ),\n v,\n r,\n s\n );\n\n require(recoveredAddress != address(0) && recoveredAddress == owner, \"INVALID_SIGNER\");\n\n allowance[recoveredAddress][spender] = value;\n }\n\n emit Approval(owner, spender, value);\n }\n\n function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {\n return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();\n }\n\n function computeDomainSeparator() internal view virtual returns (bytes32) {\n return\n keccak256(\n abi.encode(\n keccak256(\"EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)\"),\n keccak256(bytes(name)),\n keccak256(\"1\"),\n block.chainid,\n address(this)\n )\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 amount) internal virtual {\n totalSupply += amount;\n\n // Cannot overflow because the sum of all user\n // balances can't exceed the max uint256 value.\n unchecked {\n balanceOf[to] += amount;\n }\n\n emit Transfer(address(0), to, amount);\n }\n\n function _burn(address from, uint256 amount) internal virtual {\n balanceOf[from] -= amount;\n\n // Cannot underflow because a user's balance\n // will never be larger than the total supply.\n unchecked {\n totalSupply -= amount;\n }\n\n emit Transfer(from, address(0), amount);\n }\n}\n"
},
"@rari-capital/solmate/src/tokens/ERC721.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Modern, minimalist, and gas efficient ERC-721 implementation.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721 {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event Transfer(address indexed from, address indexed to, uint256 indexed id);\n\n event Approval(address indexed owner, address indexed spender, uint256 indexed id);\n\n event ApprovalForAll(address indexed owner, address indexed operator, bool approved);\n\n /*//////////////////////////////////////////////////////////////\n METADATA STORAGE/LOGIC\n //////////////////////////////////////////////////////////////*/\n\n string public name;\n\n string public symbol;\n\n function tokenURI(uint256 id) public view virtual returns (string memory);\n\n /*//////////////////////////////////////////////////////////////\n ERC721 BALANCE/OWNER STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) internal _ownerOf;\n\n mapping(address => uint256) internal _balanceOf;\n\n function ownerOf(uint256 id) public view virtual returns (address owner) {\n require((owner = _ownerOf[id]) != address(0), \"NOT_MINTED\");\n }\n\n function balanceOf(address owner) public view virtual returns (uint256) {\n require(owner != address(0), \"ZERO_ADDRESS\");\n\n return _balanceOf[owner];\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 APPROVAL STORAGE\n //////////////////////////////////////////////////////////////*/\n\n mapping(uint256 => address) public getApproved;\n\n mapping(address => mapping(address => bool)) public isApprovedForAll;\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(string memory _name, string memory _symbol) {\n name = _name;\n symbol = _symbol;\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC721 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function approve(address spender, uint256 id) public virtual {\n address owner = _ownerOf[id];\n\n require(msg.sender == owner || isApprovedForAll[owner][msg.sender], \"NOT_AUTHORIZED\");\n\n getApproved[id] = spender;\n\n emit Approval(owner, spender, id);\n }\n\n function setApprovalForAll(address operator, bool approved) public virtual {\n isApprovedForAll[msg.sender][operator] = approved;\n\n emit ApprovalForAll(msg.sender, operator, approved);\n }\n\n function transferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n require(from == _ownerOf[id], \"WRONG_FROM\");\n\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(\n msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id],\n \"NOT_AUTHORIZED\"\n );\n\n // Underflow of the sender's balance is impossible because we check for\n // ownership above and the recipient's balance can't realistically overflow.\n unchecked {\n _balanceOf[from]--;\n\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n delete getApproved[id];\n\n emit Transfer(from, to, id);\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id\n ) public virtual {\n transferFrom(from, to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function safeTransferFrom(\n address from,\n address to,\n uint256 id,\n bytes calldata data\n ) public virtual {\n transferFrom(from, to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n /*//////////////////////////////////////////////////////////////\n ERC165 LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {\n return\n interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165\n interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721\n interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL MINT/BURN LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _mint(address to, uint256 id) internal virtual {\n require(to != address(0), \"INVALID_RECIPIENT\");\n\n require(_ownerOf[id] == address(0), \"ALREADY_MINTED\");\n\n // Counter overflow is incredibly unrealistic.\n unchecked {\n _balanceOf[to]++;\n }\n\n _ownerOf[id] = to;\n\n emit Transfer(address(0), to, id);\n }\n\n function _burn(uint256 id) internal virtual {\n address owner = _ownerOf[id];\n\n require(owner != address(0), \"NOT_MINTED\");\n\n // Ownership check above ensures no underflow.\n unchecked {\n _balanceOf[owner]--;\n }\n\n delete _ownerOf[id];\n\n delete getApproved[id];\n\n emit Transfer(owner, address(0), id);\n }\n\n /*//////////////////////////////////////////////////////////////\n INTERNAL SAFE MINT LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function _safeMint(address to, uint256 id) internal virtual {\n _mint(to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, \"\") ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n\n function _safeMint(\n address to,\n uint256 id,\n bytes memory data\n ) internal virtual {\n _mint(to, id);\n\n require(\n to.code.length == 0 ||\n ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) ==\n ERC721TokenReceiver.onERC721Received.selector,\n \"UNSAFE_RECIPIENT\"\n );\n }\n}\n\n/// @notice A generic interface for a contract which properly accepts ERC721 tokens.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC721.sol)\nabstract contract ERC721TokenReceiver {\n function onERC721Received(\n address,\n address,\n uint256,\n bytes calldata\n ) external virtual returns (bytes4) {\n return ERC721TokenReceiver.onERC721Received.selector;\n }\n}\n"
},
"contracts/universal/Transactor.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { Owned } from \"@rari-capital/solmate/src/auth/Owned.sol\";\n\n/**\n * @title Transactor\n * @notice Transactor is a minimal contract that can send transactions.\n */\ncontract Transactor is Owned {\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) Owned(_owner) {}\n\n /**\n * Sends a CALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @param _value ETH value to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function CALL(\n address _target,\n bytes memory _data,\n uint256 _gas,\n uint256 _value\n ) external payable onlyOwner returns (bool, bytes memory) {\n return _target.call{ gas: _gas, value: _value }(_data);\n }\n\n /**\n * Sends a DELEGATECALL to a target address.\n *\n * @param _target Address to call.\n * @param _data Data to send with the call.\n * @param _gas Amount of gas to send with the call.\n * @return Boolean success value.\n * @return Bytes data returned by the call.\n */\n function DELEGATECALL(\n address _target,\n bytes memory _data,\n uint256 _gas\n ) external payable onlyOwner returns (bool, bytes memory) {\n // slither-disable-next-line controlled-delegatecall\n return _target.delegatecall{ gas: _gas }(_data);\n }\n}\n"
},
"@rari-capital/solmate/src/auth/Owned.sol": {
"content": "// SPDX-License-Identifier: AGPL-3.0-only\npragma solidity >=0.8.0;\n\n/// @notice Simple single owner authorization mixin.\n/// @author Solmate (https://github.com/Rari-Capital/solmate/blob/main/src/auth/Owned.sol)\nabstract contract Owned {\n /*//////////////////////////////////////////////////////////////\n EVENTS\n //////////////////////////////////////////////////////////////*/\n\n event OwnerUpdated(address indexed user, address indexed newOwner);\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP STORAGE\n //////////////////////////////////////////////////////////////*/\n\n address public owner;\n\n modifier onlyOwner() virtual {\n require(msg.sender == owner, \"UNAUTHORIZED\");\n\n _;\n }\n\n /*//////////////////////////////////////////////////////////////\n CONSTRUCTOR\n //////////////////////////////////////////////////////////////*/\n\n constructor(address _owner) {\n owner = _owner;\n\n emit OwnerUpdated(address(0), _owner);\n }\n\n /*//////////////////////////////////////////////////////////////\n OWNERSHIP LOGIC\n //////////////////////////////////////////////////////////////*/\n\n function setOwner(address newOwner) public virtual onlyOwner {\n owner = newOwner;\n\n emit OwnerUpdated(msg.sender, newOwner);\n }\n}\n"
},
"contracts/universal/drippie/Drippie.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { AssetReceiver } from \"../AssetReceiver.sol\";\nimport { IDripCheck } from \"./IDripCheck.sol\";\n\n/**\n * @title Drippie\n * @notice Drippie is a system for managing automated contract interactions. A specific interaction\n * is called a \"drip\" and can be executed according to some condition (called a dripcheck) and an\n * execution interval. Drips cannot be executed faster than the execution interval. Drips can\n * trigger arbitrary contract calls where the calling contract is this contract address. Drips can\n * also send ETH value, which makes them ideal for keeping addresses sufficiently funded with ETH.\n * Drippie is designed to be connected with smart contract automation services so that drips can be\n * executed automatically. However, Drippie is specifically designed to be separated from these\n * services so that trust assumptions are better compartmentalized.\n */\ncontract Drippie is AssetReceiver {\n /**\n * Enum representing different status options for a given drip.\n */\n enum DripStatus {\n NONE,\n ACTIVE,\n PAUSED,\n ARCHIVED\n }\n\n /**\n * Represents a drip action.\n */\n struct DripAction {\n address payable target;\n bytes data;\n uint256 value;\n }\n\n /**\n * Represents the configuration for a given drip.\n */\n struct DripConfig {\n uint256 interval;\n IDripCheck dripcheck;\n bytes checkparams;\n DripAction[] actions;\n }\n\n /**\n * Represents the state of an active drip.\n */\n struct DripState {\n DripStatus status;\n DripConfig config;\n uint256 last;\n }\n\n /**\n * Emitted when a new drip is created.\n */\n event DripCreated(string indexed name, DripConfig config);\n\n /**\n * Emitted when a drip status is updated.\n */\n event DripStatusUpdated(string indexed name, DripStatus status);\n\n /**\n * Emitted when a drip is executed.\n */\n event DripExecuted(string indexed name, address indexed executor, uint256 timestamp);\n\n /**\n * Maps from drip names to drip states.\n */\n mapping(string => DripState) public drips;\n\n /**\n * @param _owner Initial contract owner.\n */\n constructor(address _owner) AssetReceiver(_owner) {}\n\n /**\n * Creates a new drip with the given name and configuration. Once created, drips cannot be\n * modified in any way (this is a security measure). If you want to update a drip, simply pause\n * (and potentially archive) the existing drip and create a new one.\n *\n * @param _name Name of the drip.\n * @param _config Configuration for the drip.\n */\n function create(string memory _name, DripConfig memory _config) external onlyOwner {\n // Make sure this drip doesn't already exist. We *must* guarantee that no other function\n // will ever set the status of a drip back to NONE after it's been created. This is why\n // archival is a separate status.\n require(\n drips[_name].status == DripStatus.NONE,\n \"Drippie: drip with that name already exists\"\n );\n\n // We initialize this way because Solidity won't let us copy arrays into storage yet.\n DripState storage state = drips[_name];\n state.status = DripStatus.PAUSED;\n state.config.interval = _config.interval;\n state.config.dripcheck = _config.dripcheck;\n state.config.checkparams = _config.checkparams;\n\n // Solidity doesn't let us copy arrays into storage, so we push each array one by one.\n for (uint256 i = 0; i < _config.actions.length; i++) {\n state.config.actions.push(_config.actions[i]);\n }\n\n // Tell the world!\n emit DripCreated(_name, _config);\n }\n\n /**\n * Sets the status for a given drip. The behavior of this function depends on the status that\n * the user is trying to set. A drip can always move between ACTIVE and PAUSED, but it can\n * never move back to NONE and once ARCHIVED, it can never move back to ACTIVE or PAUSED.\n *\n * @param _name Name of the drip to update.\n * @param _status New drip status.\n */\n function status(string memory _name, DripStatus _status) external onlyOwner {\n // Make sure we can never set drip status back to NONE. A simple security measure to\n // prevent accidental overwrites if this code is ever updated down the line.\n require(\n _status != DripStatus.NONE,\n \"Drippie: drip status can never be set back to NONE after creation\"\n );\n\n // Make sure the drip in question actually exists. Not strictly necessary but there doesn't\n // seem to be any clear reason why you would want to do this, and it may save some gas in\n // the case of a front-end bug.\n require(\n drips[_name].status != DripStatus.NONE,\n \"Drippie: drip with that name does not exist\"\n );\n\n // Once a drip has been archived, it cannot be un-archived. This is, after all, the entire\n // point of archiving a drip.\n require(\n drips[_name].status != DripStatus.ARCHIVED,\n \"Drippie: drip with that name has been archived\"\n );\n\n // Although not strictly necessary, we make sure that the status here is actually changing.\n // This may save the client some gas if there's a front-end bug and the user accidentally\n // tries to \"change\" the status to the same value as before.\n require(\n drips[_name].status != _status,\n \"Drippie: cannot set drip status to same status as before\"\n );\n\n // If the user is trying to archive this drip, make sure the drip has been paused. We do\n // not allow users to archive active drips so that the effects of this action are more\n // abundantly clear.\n if (_status == DripStatus.ARCHIVED) {\n require(\n drips[_name].status == DripStatus.PAUSED,\n \"Drippie: drip must be paused to be archived\"\n );\n }\n\n // If we made it here then we can safely update the status.\n drips[_name].status = _status;\n emit DripStatusUpdated(_name, drips[_name].status);\n }\n\n /**\n * Triggers a drip. This function is deliberately left as a public function because the\n * assumption being made here is that setting the drip to ACTIVE is an affirmative signal that\n * the drip should be executable according to the drip parameters, drip check, and drip\n * interval. Note that drip parameters are read entirely from the state and are not supplied as\n * user input, so there should not be any way for a non-authorized user to influence the\n * behavior of the drip.\n *\n * @param _name Name of the drip to trigger.\n */\n function drip(string memory _name) external {\n DripState storage state = drips[_name];\n\n // Only allow active drips to be executed, an obvious security measure.\n require(\n state.status == DripStatus.ACTIVE,\n \"Drippie: selected drip does not exist or is not currently active\"\n );\n\n // Don't drip if the drip interval has not yet elapsed since the last time we dripped. This\n // is a safety measure that prevents a malicious recipient from, e.g., spending all of\n // their funds and repeatedly requesting new drips. Limits the potential impact of a\n // compromised recipient to just a single drip interval, after which the drip can be paused\n // by the owner address.\n require(\n state.last + state.config.interval <= block.timestamp,\n \"Drippie: drip interval has not elapsed since last drip\"\n );\n\n // Make sure we're allowed to execute this drip.\n require(\n state.config.dripcheck.check(state.config.checkparams),\n \"Drippie: dripcheck failed so drip is not yet ready to be triggered\"\n );\n\n // Update the last execution time for this drip before the call. Note that it's entirely\n // possible for a drip to be executed multiple times per block or even multiple times\n // within the same transaction (via re-entrancy) if the drip interval is set to zero. Users\n // should set a drip interval of 1 if they'd like the drip to be executed only once per\n // block (since this will then prevent re-entrancy).\n state.last = block.timestamp;\n\n // Execute each action in the drip. We allow drips to have multiple actions because there\n // are scenarios in which a contract must do multiple things atomically. For example, the\n // contract may need to withdraw ETH from one account and then deposit that ETH into\n // another account within the same transaction.\n uint256 len = state.config.actions.length;\n for (uint256 i = 0; i < len; i++) {\n // Must be marked as \"storage\" because copying structs into memory is not yet supported\n // by Solidity. Won't significantly reduce gas costs but at least makes it easier to\n // read what the rest of this section is doing.\n DripAction storage action = state.config.actions[i];\n\n // Actually execute the action. We could use ExcessivelySafeCall here but not strictly\n // necessary (worst case, a drip gets bricked IFF the target is malicious, doubt this\n // will ever happen in practice). Could save a marginal amount of gas to ignore the\n // returndata.\n // slither-disable-next-line calls-loop\n (bool success, ) = action.target.call{ value: action.value }(action.data);\n\n // Generally should not happen, but could if there's a misconfiguration (e.g., passing\n // the wrong data to the target contract), the recipient is not payable, or\n // insufficient gas was supplied to this transaction. We revert so the drip can be\n // fixed and triggered again later. Means we cannot emit an event to alert of the\n // failure, but can reasonably be detected by off-chain services even without an event.\n // Note that this forces the drip executor to supply sufficient gas to the call\n // (assuming there is some sufficient gas limit that exists, otherwise the drip will\n // not execute).\n require(\n success,\n \"Drippie: drip was unsuccessful, please check your configuration for mistakes\"\n );\n }\n\n emit DripExecuted(_name, msg.sender, block.timestamp);\n }\n}\n"
},
"contracts/universal/drippie/IDripCheck.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\ninterface IDripCheck {\n // DripCheck contracts that want to take parameters as inputs MUST expose a struct called\n // Params and an event _EventForExposingParamsStructInABI(Params params). This makes it\n // possible to easily encode parameters on the client side. Solidity does not support generics\n // so it's not possible to do this with explicit typing.\n\n function check(bytes memory _params) external view returns (bool);\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckTrue.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckTrue\n * @notice DripCheck that always returns true.\n */\ncontract CheckTrue is IDripCheck {\n function check(bytes memory) external pure returns (bool) {\n return true;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckGelatoLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\ninterface IGelatoTreasury {\n function userTokenBalance(address _user, address _token) external view returns (uint256);\n}\n\n/**\n * @title CheckGelatoLow\n * @notice DripCheck for checking if an account's Gelato ETH balance is below some threshold.\n */\ncontract CheckGelatoLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address treasury;\n uint256 threshold;\n address recipient;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check GelatoTreasury ETH balance is below threshold.\n return\n IGelatoTreasury(params.treasury).userTokenBalance(\n params.recipient,\n // Gelato represents ETH as 0xeeeee....eeeee\n 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE\n ) < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceLow.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceLow\n * @notice DripCheck for checking if an account's balance is below a given threshold.\n */\ncontract CheckBalanceLow is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target ETH balance is below threshold.\n return params.target.balance < params.threshold;\n }\n}\n"
},
"contracts/universal/drippie/dripchecks/CheckBalanceHigh.sol": {
"content": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.9;\n\nimport { IDripCheck } from \"../IDripCheck.sol\";\n\n/**\n * @title CheckBalanceHigh\n * @notice DripCheck for checking if an account's balance is above a given threshold.\n */\ncontract CheckBalanceHigh is IDripCheck {\n event _EventToExposeStructInABI__Params(Params params);\n struct Params {\n address target;\n uint256 threshold;\n }\n\n function check(bytes memory _params) external view returns (bool) {\n Params memory params = abi.decode(_params, (Params));\n\n // Check target balance is above threshold.\n return params.target.balance > params.threshold;\n }\n}\n"
}
},
"settings": {
"optimizer": {
"enabled": true,
"runs": 10000
},
"outputSelection": {
"*": {
"*": [
"abi",
"evm.bytecode",
"evm.deployedBytecode",
"evm.methodIdentifiers",
"metadata",
"devdoc",
"userdoc",
"storageLayout",
"evm.gasEstimates"
],
"": [
"ast"
]
}
},
"metadata": {
"useLiteralContent": true
}
}
}
\ No newline at end of file
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
[profile.default]
# The source directory
src = 'contracts/universal'
# The test directory
test = 'contracts/foundry-tests'
# We need to build seperate artifacts for forge and hh, because they each expect a different
# structure for the artifacts directory.
# The artifact directory
out = 'forge-artifacts'
# Enables or disables the optimizer
optimizer = true
# The number of optimizer runs
optimizer_runs = 200
# A list of remappings
remappings = [
'@rari-capital/solmate/=node_modules/@rari-capital/solmate',
'forge-std/=node_modules/forge-std/src',
'ds-test/=node_modules/ds-test/src',
'multicall/=lib/multicall',
'@openzeppelin/contracts/=node_modules/@openzeppelin/contracts/',
'@openzeppelin/contracts-upgradeable/=node_modules/@openzeppelin/contracts-upgradeable/',
'@eth-optimism/contracts-bedrock/=node_modules/@eth-optimism/contracts-bedrock',
]
allow_paths = ["../../node_modules", "./**"]
# The metadata hash can be removed from the bytecode by setting "none"
bytecode_hash = "none"
libs = ["node_modules", "lib"]
# Required to use `deployCode` to deploy the multicall contract which has incompatible version
fs_permissions = [{ access = "read", path = "./forge-artifacts/Multicall3.sol/Multicall3.json"}]
import assert from 'assert'
import { HardhatUserConfig, subtask } from 'hardhat/config'
import { TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS } from 'hardhat/builtin-tasks/task-names'
import { getenv } from '@eth-optimism/core-utils'
import * as dotenv from 'dotenv'
import { configSpec } from './src/config/deploy'
// Hardhat plugins
import '@nomiclabs/hardhat-ethers'
import '@nomiclabs/hardhat-waffle'
import '@nomiclabs/hardhat-etherscan'
import '@eth-optimism/hardhat-deploy-config'
import '@typechain/hardhat'
import 'solidity-coverage'
import 'hardhat-gas-reporter'
import 'hardhat-deploy'
// Hardhat tasks
import './tasks'
// Load environment variables from .env
dotenv.config()
subtask(TASK_COMPILE_SOLIDITY_GET_SOURCE_PATHS).setAction(
async (_, __, runSuper) => {
const paths = await runSuper()
return paths.filter((p: string) => !p.endsWith('.t.sol'))
}
)
assert(
!(getenv('PRIVATE_KEY') && getenv('LEDGER_ADDRESS')),
'use only one of PRIVATE_KEY or LEDGER_ADDRESS'
)
const accounts = getenv('PRIVATE_KEY')
? [getenv('PRIVATE_KEY')]
: (undefined as any)
const config: HardhatUserConfig = {
networks: {
optimism: {
chainId: 10,
url: 'https://mainnet.optimism.io',
accounts,
verify: {
etherscan: {
apiKey: getenv('OPTIMISTIC_ETHERSCAN_API_KEY'),
},
},
companionNetworks: {
l1: 'mainnet',
},
},
'optimism-goerli': {
chainId: 420,
url: 'https://goerli.optimism.io',
accounts,
verify: {
etherscan: {
apiKey: getenv('OPTIMISTIC_ETHERSCAN_API_KEY'),
},
},
companionNetworks: {
l1: 'goerli',
},
},
mainnet: {
chainId: 1,
url: `https://mainnet.infura.io/v3/${getenv('INFURA_PROJECT_ID')}`,
accounts,
verify: {
etherscan: {
apiKey: getenv('ETHEREUM_ETHERSCAN_API_KEY'),
},
},
companionNetworks: {
l2: 'optimism',
},
},
goerli: {
chainId: 5,
url: `https://goerli.infura.io/v3/${getenv('INFURA_PROJECT_ID')}`,
accounts,
verify: {
etherscan: {
apiKey: getenv('ETHEREUM_ETHERSCAN_API_KEY'),
},
},
companionNetworks: {
l2: 'optimism-goerli',
},
},
ropsten: {
chainId: 3,
url: `https://ropsten.infura.io/v3/${getenv('INFURA_PROJECT_ID')}`,
accounts,
verify: {
etherscan: {
apiKey: getenv('ETHEREUM_ETHERSCAN_API_KEY'),
},
},
},
'ops-l2': {
chainId: 17,
accounts: [
'0x3b8d2345102cce2443acb240db6e87c8edd4bb3f821b17fab8ea2c9da08ea132',
'0xa6aecc98b63bafb0de3b29ae9964b14acb4086057808be29f90150214ebd4a0f',
],
url: 'http://127.0.0.1:8545',
companionNetworks: {
l1: 'ops-l1',
},
},
'ops-l1': {
chainId: 31337,
accounts: [
'0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80',
],
url: 'http://127.0.0.1:9545',
companionNetworks: {
l2: 'ops-l2',
},
},
},
paths: {
deployConfig: './config/deploy',
},
external: {
contracts: [
{
artifacts: '../contracts/artifacts',
},
],
deployments: {
goerli: ['../contracts/deployments/goerli'],
mainnet: ['../contracts/deployments/mainnet'],
},
},
deployConfigSpec: configSpec,
mocha: {
timeout: 50000,
},
typechain: {
outDir: 'dist/types',
target: 'ethers-v5',
},
solidity: {
compilers: [
{
version: '0.8.16',
settings: {
optimizer: { enabled: true, runs: 10_000 },
},
},
{
version: '0.8.15',
settings: {
optimizer: { enabled: true, runs: 10_000 },
},
},
],
settings: {
metadata: {
bytecodeHash: 'none',
},
outputSelection: {
'*': {
'*': ['metadata', 'storageLayout'],
},
},
},
},
namedAccounts: {
deployer: {
default: getenv('LEDGER_ADDRESS')
? `ledger://${getenv('LEDGER_ADDRESS')}`
: 0,
hardhat: 0,
},
},
}
export default config
Subproject commit a1fa0644fa412cd3237ef7081458ecb2ffad7dbe
{
"name": "@eth-optimism/contracts-periphery",
"version": "1.0.8",
"description": "[Optimism] External (out-of-protocol) L1 and L2 smart contracts for Optimism",
"main": "dist/index",
"types": "dist/index",
"files": [
"dist/**/*.js",
"dist/**/*.d.ts",
"dist/types",
"artifacts/contracts/**/*.json",
"deployments/**/*.json",
"contracts"
],
"scripts": {
"build": "pnpm build:hh",
"build:hh": "hardhat compile --show-stack-traces",
"build:forge": "forge build",
"test": "pnpm test:forge",
"test:forge": "forge test",
"test:coverage": "pnpm test:coverage:forge",
"test:coverage:forge": "forge coverage",
"test:slither": "slither .",
"gas-snapshot": "forge snapshot",
"pretest:slither": "rm -f @openzeppelin && rm -f hardhat && ln -s node_modules/@openzeppelin @openzeppelin && ln -s ../../node_modules/hardhat hardhat",
"posttest:slither": "rm -f @openzeppelin && rm -f hardhat",
"lint:ts:check": "eslint . --max-warnings=0",
"lint:contracts:check": "pnpm solhint -f table 'contracts/**/*.sol'",
"lint:check": "pnpm lint:contracts:check && pnpm lint:ts:check",
"lint:ts:fix": "eslint --fix .",
"lint:contracts:fix": "pnpm prettier --write 'contracts/**/*.sol'",
"lint:fix": "pnpm lint:contracts:fix && pnpm lint:ts:fix",
"lint": "pnpm lint:fix && pnpm lint:check",
"clean": "rm -rf ./dist ./artifacts ./forge-artifacts ./cache ./coverage ./tsconfig.tsbuildinfo",
"prepublishOnly": "pnpm copyfiles -u 1 -e \"**/test-*/**/*\" \"contracts/**/*\" ./",
"postpublish": "rimraf chugsplash L1 L2 libraries standards",
"prepack": "pnpm prepublishOnly",
"postpack": "pnpm postpublish",
"pre-commit": "lint-staged"
},
"keywords": [
"optimism",
"ethereum",
"contracts",
"periphery",
"solidity"
],
"homepage": "https://github.com/ethereum-optimism/optimism/tree/develop/packages/contracts-periphery#readme",
"license": "MIT",
"author": "Optimism PBC",
"repository": {
"type": "git",
"url": "https://github.com/ethereum-optimism/optimism.git"
},
"devDependencies": {
"@eth-optimism/contracts-bedrock": "0.15.0",
"@eth-optimism/core-utils": "^0.12.1",
"@eth-optimism/hardhat-deploy-config": "^0.2.6",
"@ethersproject/hardware-wallets": "^5.7.0",
"@nomiclabs/hardhat-ethers": "^2.0.2",
"@nomiclabs/hardhat-etherscan": "^3.0.3",
"@nomiclabs/hardhat-waffle": "^2.0.3",
"@openzeppelin/contracts": "4.7.3",
"@openzeppelin/contracts-upgradeable": "4.7.3",
"@rari-capital/solmate": "7.0.0-alpha.3",
"@typechain/ethers-v5": "^10.1.0",
"@typechain/hardhat": "^6.1.2",
"@types/node": "^17.0.21",
"babel-eslint": "^10.1.0",
"chai": "^4.3.4",
"copyfiles": "^2.3.0",
"dotenv": "^10.0.0",
"ethereum-waffle": "^3.4.4",
"ethers": "^5.7.0",
"hardhat": "^2.9.6",
"hardhat-deploy": "^0.11.10",
"hardhat-gas-reporter": "^1.0.8",
"lint-staged": "11.0.0",
"mkdirp": "^1.0.4",
"node-fetch": "^2.6.7",
"prettier": "^2.8.0",
"prettier-plugin-solidity": "^1.0.0-beta.18",
"solhint": "^3.3.6",
"solhint-plugin-prettier": "^0.0.5",
"solidity-coverage": "^0.7.17",
"ts-node": "^10.9.1",
"typechain": "^8.1.0"
},
"dependencies": {
"ds-test": "github:dapphub/ds-test#c9ce3f25bde29fc5eb9901842bf02850dfd2d084",
"forge-std": "github:foundry-rs/forge-std#e8a047e3f40f13fa37af6fe14e6e06283d9a060e"
}
}
{
"detectors_to_exclude": "conformance-to-solidity-naming-conventions,assembly-usage,low-level-calls,block-timestamp,pragma,solc-version,too-many-digits,boolean-equal,missing-zero-check",
"exclude_informational": false,
"exclude_low": false,
"exclude_medium": false,
"exclude_high": false,
"solc_disable_warnings": false,
"hardhat_ignore_compile": false,
"disable_color": false,
"exclude_dependencies": false,
"filter_paths": "@openzeppelin|hardhat|contracts/testing"
}
import { DeployConfigSpec } from '@eth-optimism/hardhat-deploy-config/dist/src/types'
/**
* Defines the configuration for a deployment.
*/
export interface DeployConfig {
/**
* Dedicated Deterministic Deployer address (DDD).
* When deploying authenticated deterministic smart contracts to the same address on various
* chains, it's necessary to have a single root address that will initially own the contract and
* later transfer ownership to the final contract owner. We call this address the DDD. We expect
* the DDD to transfer ownership to the final contract owner very quickly after deployment.
*/
ddd: string
/**
* Number of confs before considering it final
*/
numDeployConfirmations?: number
/**
* Name of the NFT in the Optimist contract.
*/
optimistName: string
/**
* Symbol of the NFT in the Optimist contract.
*/
optimistSymbol: string
/**
* Address of the privileged attestor for the Optimist contract.
*/
optimistBaseUriAttestorAddress: string
/**
* Address of the privileged account for the OptimistInviter contract that can grant invites.
*/
optimistInviterInviteGranter: string
/**
* Name of OptimistInviter contract, used for the EIP712 domain separator.
*/
optimistInviterName: string
/**
* Address of previleged account for the OptimistAllowlist contract that can add/remove people
* from allowlist.
*/
optimistAllowlistAllowlistAttestor: string
/**
* Address of Coinbase attestor that attests to whether someone has completed Quest.
*/
optimistAllowlistCoinbaseQuestAttestor: string
/**
* Address of the owner of the proxies on L2. There will be a ProxyAdmin deployed as a predeploy
* after bedrock, so the owner of proxies should be updated to that after the upgrade.
* This currently is used as the owner of the nft related proxies.
*/
l2ProxyOwnerAddress: string
}
/**
* Specification for each of the configuration options.
*/
export const configSpec: DeployConfigSpec<DeployConfig> = {
ddd: {
type: 'address',
},
numDeployConfirmations: {
type: 'number',
default: 1,
},
optimistName: {
type: 'string',
default: 'Optimist',
},
optimistSymbol: {
type: 'string',
default: 'OPTIMIST',
},
optimistBaseUriAttestorAddress: {
type: 'address',
},
optimistInviterInviteGranter: {
type: 'address',
},
optimistInviterName: {
type: 'string',
},
optimistAllowlistAllowlistAttestor: {
type: 'address',
},
optimistAllowlistCoinbaseQuestAttestor: {
type: 'address',
},
l2ProxyOwnerAddress: {
type: 'address',
},
}
import assert from 'assert'
import { BigNumberish, ethers } from 'ethers'
import { Interface } from 'ethers/lib/utils'
import { HardhatRuntimeEnvironment } from 'hardhat/types'
import { Etherscan } from '../etherscan'
export interface DripConfig {
reentrant?: boolean
interval: BigNumberish
dripcheck: string
checkparams?: any
actions: Array<{
target: string
value?: BigNumberish
data?:
| string
| {
fn: string
args?: any[]
}
}>
}
export interface DrippieConfig {
[name: string]: DripConfig
}
export enum Time {
SECOND = 1,
MINUTE = 60 * Time.SECOND,
HOUR = 60 * Time.MINUTE,
DAY = 24 * Time.HOUR,
WEEK = 7 * Time.DAY,
}
export const getDrippieConfig = async (
hre: HardhatRuntimeEnvironment
): Promise<Required<DrippieConfig>> => {
let config: DrippieConfig
try {
// eslint-disable-next-line @typescript-eslint/no-var-requires
config = require(`../../config/drippie/${hre.network.name}.ts`).default
} catch (err) {
throw new Error(
`error while loading drippie config for network: ${hre.network.name}, ${err}`
)
}
return parseDrippieConfig(hre, config)
}
export const encodeDripCheckParams = (
iface: Interface,
params: any
): string => {
return ethers.utils.defaultAbiCoder.encode(
[iface.getEvent('_EventToExposeStructInABI__Params').inputs[0]],
[params]
)
}
export const parseDrippieConfig = async (
hre: HardhatRuntimeEnvironment,
config: DrippieConfig
): Promise<Required<DrippieConfig>> => {
// Create a clone of the config object. Shallow clone is fine because none of the input options
// are expected to be objects or functions etc.
const parsed = { ...config }
const etherscan = new Etherscan(
hre.network.config.verify.etherscan.apiKey,
hre.network.config.chainId
)
for (const dripConfig of Object.values(parsed)) {
for (const action of dripConfig.actions) {
assert(ethers.utils.isAddress(action.target), 'target is not an address')
if (action.data === undefined) {
action.data = '0x'
} else if (typeof action.data === 'string') {
assert(
ethers.utils.isHexString(action.data),
'action is not a hex string'
)
} else {
const abi = await etherscan.getContractABI(action.target)
const iface = new ethers.utils.Interface(abi)
action.data = iface.encodeFunctionData(
action.data.fn,
action.data.args || []
)
}
if (action.value === undefined) {
action.value = ethers.BigNumber.from(0)
} else {
action.value = ethers.BigNumber.from(action.value)
}
}
const dripcheck = await hre.deployments.get(dripConfig.dripcheck)
dripConfig.dripcheck = dripcheck.address
if (dripConfig.checkparams === undefined) {
dripConfig.checkparams = '0x'
} else {
dripConfig.checkparams = encodeDripCheckParams(
new ethers.utils.Interface(dripcheck.abi),
dripConfig.checkparams
)
}
dripConfig.interval = ethers.BigNumber.from(dripConfig.interval)
dripConfig.reentrant = dripConfig.reentrant || false
}
return parsed as Required<DrippieConfig>
}
export const isSameConfig = (a: DripConfig, b: DripConfig): boolean => {
return (
a.dripcheck.toLowerCase() === b.dripcheck.toLowerCase() &&
a.checkparams === b.checkparams &&
ethers.BigNumber.from(a.interval).eq(b.interval) &&
a.actions.length === b.actions.length &&
a.actions.every((ax, i) => {
return (
ax.target === b.actions[i].target &&
ax.data === b.actions[i].data &&
ethers.BigNumber.from(ax.value).eq(b.actions[i].value)
)
})
)
}
export * from './deploy'
export * from './drippie'
export * from './config'
export * from './etherscan'
export * from './gnosis-safe-checksum'
export * from './install-drippie-config'
export * from './install-drippie-config-multisig'
import fs from 'fs'
import { task } from 'hardhat/config'
import { getChainId } from '@eth-optimism/core-utils'
import { isSameConfig, getDrippieConfig, addChecksum } from '../src'
task('install-drippie-config-multisig')
.addParam('safe', 'address of the Gnosis Safe to execute this bundle')
.addParam('outfile', 'where to write the bundle JSON file')
.setAction(async (args, hre) => {
if (!hre.ethers.utils.isAddress(args.safe)) {
throw new Error(`given safe is not an address: ${args.safe}`)
}
console.log(`connecting to Drippie...`)
const Drippie = await hre.ethers.getContractAt(
'Drippie',
(
await hre.deployments.get('Drippie')
).address
)
console.log(`loading local version of Drippie config for network...`)
const config = await getDrippieConfig(hre)
// Gnosis Safe transaction bundle.
const bundle: any = {
version: '1.0',
chainId: (await getChainId(hre.ethers.provider)).toString(),
createdAt: Date.now(),
meta: {
name: 'Transactions Batch',
description: '',
txBuilderVersion: '1.8.0',
createdFromSafeAddress: args.safe,
createdFromOwnerAddress: '',
},
transactions: [],
}
console.log(`generating transaction bundle...`)
for (const [dripName, dripConfig] of Object.entries(config)) {
console.log(`checking config for drip: ${dripName}`)
const drip = await Drippie.drips(dripName)
if (drip.status === 0) {
console.log(`drip does not exist yet: ${dripName}`)
console.log(`adding drip creation to bundle...`)
bundle.transactions.push({
to: Drippie.address,
value: '0',
data: null,
contractMethod: {
inputs: [
{ internalType: 'string', name: '_name', type: 'string' },
{
components: [
{
internalType: 'uint256',
name: 'interval',
type: 'uint256',
},
{
internalType: 'contract IDripCheck',
name: 'dripcheck',
type: 'address',
},
{ internalType: 'bytes', name: 'checkparams', type: 'bytes' },
{
components: [
{
internalType: 'address payable',
name: 'target',
type: 'address',
},
{ internalType: 'bytes', name: 'data', type: 'bytes' },
{
internalType: 'uint256',
name: 'value',
type: 'uint256',
},
],
internalType: 'struct Drippie.DripAction[]',
name: 'actions',
type: 'tuple[]',
},
],
internalType: 'struct Drippie.DripConfig',
name: '_config',
type: 'tuple',
},
],
name: 'create',
payable: false,
},
contractInputsValues: {
_name: dripName,
_config: JSON.stringify([
hre.ethers.BigNumber.from(dripConfig.interval).toString(),
dripConfig.dripcheck,
dripConfig.checkparams,
dripConfig.actions.map((action) => {
return [
action.target,
action.data,
hre.ethers.BigNumber.from(action.value).toString(),
]
}),
]),
},
})
} else if (!isSameConfig(dripConfig, drip.config)) {
console.log(`drip exists but local config is different: ${dripName}`)
console.log(`drips cannot be modified for security reasons`)
console.log(`please do not modify the local config for existing drips`)
console.log(`you can archive the old drip and create another`)
} else {
console.log(`drip is already installed`)
}
}
console.log(`writing bundle to ${args.outfile}...`)
fs.writeFileSync(args.outfile, JSON.stringify(addChecksum(bundle), null, 2))
})
import { task } from 'hardhat/config'
import { LedgerSigner } from '@ethersproject/hardware-wallets'
import { PopulatedTransaction } from 'ethers'
import '@nomiclabs/hardhat-ethers'
import 'hardhat-deploy'
import { isSameConfig, getDrippieConfig } from '../src'
task('install-drippie-config').setAction(async (args, hre) => {
console.log(`connecting to ledger...`)
const signer = new LedgerSigner(
hre.ethers.provider,
'default',
hre.ethers.utils.defaultPath
)
console.log(`connecting to Drippie...`)
const Drippie = await hre.ethers.getContractAt(
'Drippie',
(
await hre.deployments.get('Drippie')
).address,
signer
)
console.log(`loading local version of Drippie config for network...`)
const config = await getDrippieConfig(hre)
// Need this to deal with annoying Ethers/Ledger 1559 issue.
const sendtx = async (tx: PopulatedTransaction): Promise<void> => {
const gas = await signer.estimateGas(tx)
tx.type = 1
tx.gasLimit = gas
const ret = await signer.sendTransaction(tx)
console.log(`sent tx: ${ret.hash}`)
console.log(`waiting for tx to be confirmed...`)
await ret.wait()
console.log(`tx confirmed`)
}
console.log(`installing Drippie config file...`)
for (const [dripName, dripConfig] of Object.entries(config)) {
console.log(`checking config for drip: ${dripName}`)
const drip = await Drippie.drips(dripName)
if (drip.status === 0) {
console.log(`drip does not exist yet: ${dripName}`)
console.log(`creating drip...`)
const tx = await Drippie.populateTransaction.create(dripName, dripConfig)
await sendtx(tx)
} else if (!isSameConfig(dripConfig, drip.config)) {
console.log(`drip exists but local config is different: ${dripName}`)
console.log(`drips cannot be modified for security reasons`)
console.log(`please do not modify the local config for existing drips`)
console.log(`you can archive the old drip and create another`)
} else {
console.log(`drip is already installed`)
}
}
console.log(`config is fully installed`)
})
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"rootDir": "./src",
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
...@@ -32,19 +32,20 @@ ...@@ -32,19 +32,20 @@
"url": "https://github.com/ethereum-optimism/optimism.git" "url": "https://github.com/ethereum-optimism/optimism.git"
}, },
"dependencies": { "dependencies": {
"ethers": "^5.7.0",
"@ethersproject/abi": "^5.7.0", "@ethersproject/abi": "^5.7.0",
"@ethersproject/abstract-provider": "^5.7.0", "@ethersproject/abstract-provider": "^5.7.0",
"@ethersproject/address": "^5.7.0", "@ethersproject/address": "^5.7.0",
"@ethersproject/bignumber": "^5.7.0", "@ethersproject/bignumber": "^5.7.0",
"@ethersproject/bytes": "^5.7.0", "@ethersproject/bytes": "^5.7.0",
"@ethersproject/contracts": "^5.7.0",
"@ethersproject/constants": "^5.7.0", "@ethersproject/constants": "^5.7.0",
"@ethersproject/contracts": "^5.7.0",
"@ethersproject/keccak256": "^5.7.0", "@ethersproject/keccak256": "^5.7.0",
"@ethersproject/rlp": "^5.7.0",
"@ethersproject/properties": "^5.7.0", "@ethersproject/properties": "^5.7.0",
"@ethersproject/rlp": "^5.7.0",
"@ethersproject/web": "^5.7.0", "@ethersproject/web": "^5.7.0",
"chai": "^4.3.4" "chai": "^4.3.4",
"ethers": "^5.7.0",
"node-fetch": "^2.6.7"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^12.12.6", "@types/node": "^12.12.6",
......
export * from './common' export * from './common'
export * from './external' export * from './external'
export * from './optimism' export * from './optimism'
export * from './gnosis-safe-checksum'
export * from './etherscan'
export * from './helpers/setupProxyContract'
ignores: [
"@babel/eslint-parser",
"@typescript-eslint/parser",
"eslint-plugin-import",
"eslint-plugin-unicorn",
"eslint-plugin-jsdoc",
"eslint-plugin-prefer-arrow",
"eslint-plugin-react",
"@typescript-eslint/eslint-plugin",
"eslint-config-prettier",
"eslint-plugin-prettier",
"chai"
]
module.exports = {
extends: '../../.eslintrc.js',
}
module.exports = {
...require('../../.prettierrc.js'),
};
# @eth-optimism/hardhat-deploy-config
## 0.2.6
### Patch Changes
- 5cf646bab: Add getter for other network's deploy config
## 0.2.5
### Patch Changes
- 1d3c749a2: Bumps the version of ts-node used
## 0.2.4
### Patch Changes
- dd5ab8c0: Allow `paths` to be unset in hardhat config
## 0.2.3
### Patch Changes
- 7215f4ce: Bump ethers to 5.7.0 globally
## 0.2.2
### Patch Changes
- 6ce47f38: Support JSON-formatted deploy configs
## 0.2.1
### Patch Changes
- 2fd0a2fe: Use lazyObject
- 89d01f2e: Update dev deps
## 0.2.0
### Minor Changes
- 27234f68: Initial release of hardhat-deploy-config
### Patch Changes
- a320e744: Properly exports DeployConfigSpec type
- 29ff7462: Revert es target back to 2017
(The MIT License)
Copyright 2020-2021 Optimism
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# @eth-optimism/hardhat-deploy-config
`hardhat-deploy-config` is a simple plugin that adds support for global deploy configuration values.
## Installation
```
pnpm i @eth-optimism/hardhat-deploy-config
```
{
"name": "@eth-optimism/hardhat-deploy-config",
"version": "0.2.6",
"description": "[Optimism] Hardhat deploy configuration plugin",
"main": "dist/src/index.js",
"types": "dist/src/index.d.ts",
"files": [
"dist/*"
],
"scripts": {
"test:coverage": "echo 'No tests defined.'",
"build": "tsc -p tsconfig.json",
"clean": "rimraf dist/ ./tsconfig.tsbuildinfo",
"lint": "pnpm lint:fix && pnpm lint:check",
"pre-commit": "lint-staged",
"lint:fix": "pnpm lint:check --fix",
"lint:check": "eslint . --max-warnings=0"
},
"keywords": [
"optimism",
"ethereum",
"hardhat",
"deploy",
"config",
"plugin"
],
"homepage": "https://github.com/ethereum-optimism/optimism/tree/develop/packages/hardhat-deploy-config#readme",
"license": "MIT",
"author": "Optimism PBC",
"repository": {
"type": "git",
"url": "https://github.com/ethereum-optimism/optimism.git"
},
"devDependencies": {
"ethers": "^5.7.0",
"ts-node": "^10.9.1",
"hardhat": "^2.9.6"
}
}
import './type-extensions'
import './plugin'
import * as path from 'path'
import * as fs from 'fs'
import { extendEnvironment, extendConfig } from 'hardhat/config'
import {
HardhatConfig,
HardhatRuntimeEnvironment,
HardhatUserConfig,
} from 'hardhat/types'
import { lazyObject, lazyFunction } from 'hardhat/plugins'
import { ethers } from 'ethers'
// From: https://github.com/wighawag/hardhat-deploy/blob/master/src/index.ts#L63-L76
const normalizePath = (
config: HardhatConfig,
userPath: string | undefined,
defaultPath: string
): string => {
if (userPath === undefined) {
userPath = path.join(config.paths.root, defaultPath)
} else {
if (!path.isAbsolute(userPath)) {
userPath = path.normalize(path.join(config.paths.root, userPath))
}
}
return userPath
}
const getDeployConfig = (
dir: string,
network: string
): { [key: string]: any } => {
let config: any
try {
const base = `${dir}/${network}`
if (fs.existsSync(`${base}.ts`)) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
config = require(`${base}.ts`).default
} else if (fs.existsSync(`${base}.json`)) {
// eslint-disable-next-line @typescript-eslint/no-var-requires
config = require(`${base}.json`)
} else {
throw new Error('not found')
}
} catch (err) {
throw new Error(
`error while loading deploy config for network: ${network}, ${err}`
)
}
return config
}
export const loadDeployConfig = (hre: HardhatRuntimeEnvironment): any => {
const paths = hre.config.paths.deployConfig
const conf = getDeployConfig(paths, hre.network.name)
const spec = parseDeployConfig(hre, conf)
return new Proxy(spec, {
get: (target, prop) => {
if (target.hasOwnProperty(prop)) {
return target[prop]
}
// Explicitly throw if the property is not found
throw new Error(
`property does not exist in deploy config: ${String(prop)}`
)
},
})
}
export const parseDeployConfig = (
hre: HardhatRuntimeEnvironment,
config: any
): any => {
// Create a clone of the config object. Shallow clone is fine because none of the input options
// are expected to be objects or functions etc.
const parsed = { ...config }
// If the deployConfigSpec is not provided, do no validation
if (!hre.config.deployConfigSpec) {
return parsed
}
for (const [key, spec] of Object.entries(hre.config.deployConfigSpec)) {
// Make sure the value is defined, or use a default.
if (parsed[key] === undefined) {
if ('default' in spec) {
parsed[key] = spec.default
} else {
throw new Error(
`deploy config is missing required field: ${key} (${spec.type})`
)
}
} else {
// Make sure the default has the correct type.
if (spec.type === 'address') {
if (!ethers.utils.isAddress(parsed[key])) {
throw new Error(
`deploy config field: ${key} is not of type ${spec.type}: ${parsed[key]}`
)
}
} else if (typeof parsed[key] !== spec.type) {
throw new Error(
`deploy config field: ${key} is not of type ${spec.type}: ${parsed[key]}`
)
}
}
}
return parsed
}
extendConfig(
(config: HardhatConfig, userConfig: Readonly<HardhatUserConfig>) => {
config.paths.deployConfig = normalizePath(
config,
userConfig.paths?.deployConfig,
'deploy-config'
)
}
)
extendEnvironment((hre) => {
hre.deployConfig = lazyObject(() => loadDeployConfig(hre))
hre.getDeployConfig = lazyFunction(() => {
const paths = hre.config.paths.deployConfig
return (network: string) => getDeployConfig(paths, network)
})
})
import 'hardhat/types/runtime'
import 'hardhat/types/config'
import { DeployConfigSpec } from './types'
declare module 'hardhat/types/config' {
interface HardhatUserConfig {
deployConfigSpec?: DeployConfigSpec<any>
}
interface HardhatConfig {
deployConfigSpec?: DeployConfigSpec<any>
}
interface ProjectPathsUserConfig {
deployConfig?: string
}
interface ProjectPathsConfig {
deployConfig?: string
}
}
declare module 'hardhat/types/runtime' {
interface HardhatRuntimeEnvironment {
deployConfig: {
[key: string]: any
}
getDeployConfig(network: string): { [key: string]: any }
}
}
export type DeployConfigSpec<
TDeployConfig extends {
[key: string]: any
}
> = {
[K in keyof TDeployConfig]: {
type: 'address' | 'number' | 'string' | 'boolean'
default?: any
}
}
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "./dist"
},
"include": [
"src/**/*"
]
}
...@@ -59,11 +59,6 @@ const config: HardhatUserConfig = { ...@@ -59,11 +59,6 @@ const config: HardhatUserConfig = {
'../contracts-bedrock/deployments/goerli', '../contracts-bedrock/deployments/goerli',
'../contracts/deployments/goerli', '../contracts/deployments/goerli',
], ],
'final-migration-rehearsal': [
'../contracts-bedrock/deployments/final-migration-rehearsal',
'../contracts/deployments/goerli',
'../contracts-periphery/deployments/goerli',
],
}, },
}, },
} }
......
...@@ -30,6 +30,7 @@ export enum L2ChainID { ...@@ -30,6 +30,7 @@ export enum L2ChainID {
OPTIMISM_BEDROCK_LOCAL_DEVNET = 901, OPTIMISM_BEDROCK_LOCAL_DEVNET = 901,
OPTIMISM_BEDROCK_ALPHA_TESTNET = 28528, OPTIMISM_BEDROCK_ALPHA_TESTNET = 28528,
BASE_GOERLI = 84531, BASE_GOERLI = 84531,
BASE_MAINNET = 8453,
ZORA_GOERLI = 999, ZORA_GOERLI = 999,
ZORA_MAINNET = 7777777, ZORA_MAINNET = 7777777,
} }
......
...@@ -72,6 +72,7 @@ export const DEPOSIT_CONFIRMATION_BLOCKS: { ...@@ -72,6 +72,7 @@ export const DEPOSIT_CONFIRMATION_BLOCKS: {
[L2ChainID.OPTIMISM_BEDROCK_LOCAL_DEVNET]: 2 as const, [L2ChainID.OPTIMISM_BEDROCK_LOCAL_DEVNET]: 2 as const,
[L2ChainID.OPTIMISM_BEDROCK_ALPHA_TESTNET]: 12 as const, [L2ChainID.OPTIMISM_BEDROCK_ALPHA_TESTNET]: 12 as const,
[L2ChainID.BASE_GOERLI]: 12 as const, [L2ChainID.BASE_GOERLI]: 12 as const,
[L2ChainID.BASE_MAINNET]: 50 as const,
[L2ChainID.ZORA_GOERLI]: 12 as const, [L2ChainID.ZORA_GOERLI]: 12 as const,
[L2ChainID.ZORA_MAINNET]: 50 as const, [L2ChainID.ZORA_MAINNET]: 50 as const,
} }
...@@ -218,6 +219,22 @@ export const CONTRACT_ADDRESSES: { ...@@ -218,6 +219,22 @@ export const CONTRACT_ADDRESSES: {
}, },
l2: DEFAULT_L2_CONTRACT_ADDRESSES, l2: DEFAULT_L2_CONTRACT_ADDRESSES,
}, },
[L2ChainID.BASE_MAINNET]: {
l1: {
AddressManager: '0x8EfB6B5c4767B09Dc9AA6Af4eAA89F749522BaE2' as const,
L1CrossDomainMessenger:
'0x866E82a600A1414e583f7F13623F1aC5d58b0Afa' as const,
L1StandardBridge: '0x3154Cf16ccdb4C6d922629664174b904d80F2C35' as const,
StateCommitmentChain:
'0x0000000000000000000000000000000000000000' as const,
CanonicalTransactionChain:
'0x0000000000000000000000000000000000000000' as const,
BondManager: '0x0000000000000000000000000000000000000000' as const,
OptimismPortal: '0x49048044D57e1C92A77f79988d21Fa8fAF74E97e' as const,
L2OutputOracle: '0x56315b90c40730925ec5485cf004d835058518A0' as const,
},
l2: DEFAULT_L2_CONTRACT_ADDRESSES,
},
// Zora Goerli // Zora Goerli
[L2ChainID.ZORA_GOERLI]: { [L2ChainID.ZORA_GOERLI]: {
l1: { l1: {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
# Cannon Fault Proof Virtual Machine Specification
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->
**Table of Contents**
- [Overview](#overview)
- [State](#state)
- [Memory](#memory)
- [Heap](#heap)
- [Delay Slots](#delay-slots)
- [Syscalls](#syscalls)
- [I/O](#io)
- [Standard Streams](#standard-streams)
- [Hint Communication](#hint-communication)
- [Pre-image Communication](#pre-image-communication)
- [Pre-image I/O Alignment](#pre-image-io-alignment)
- [Exceptions](#exceptions)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
## Overview
This is a description of the Cannon Fault Proof Virtual Machine (FPVM). The Cannon FPVM emulates
a minimal Linux-based system running on big-endian 32-bit MIPS32 architecture.
Alot of its behaviors are copied from Linux/MIPS with a few tweaks made for fault proofs.
For the rest of this doc, we refer to the Cannon FPVM as simply the FPVM.
Operationally, the FPVM is a state transition function. This state transition is referred to as a *Step*,
that executes a single instruction. We say the VM is a function $f$, given an input state $S_{pre}$, steps on a
single instruction encoded in the state to produce a new state $S_{post}$.
$$f(S_{pre}) \rightarrow S_{post}$$
Thus, the trace of a program executed by the FPVM is an ordered set of VM states.
## State
The virtual machine state highlights the effects of running a Fault Proof Program on the VM.
It consists of the following fields:
1. `memRoot` - A `bytes32` value representing the merkle root of VM memory.
2. `preimageKey` - `bytes32` value of the last requested pre-image key.
3. `preimageOffset` - The 32-bit value of the last requested pre-image offset.
4. `pc` - 32-bit program counter.
5. `nextPC` - 32-bit next program counter. Note that this value may not always be $pc+4$
when executing a branch/jump delay slot.
6. `lo` - 32-bit MIPS LO special register.
7. `hi` - 32-bit MIPS HI special register.
8. `heap` - 32-bit base address of the most recent memory allocation via mmap.
9. `exitCode` - 8-bit exit code.
10. `exited` - 1-bit indicator that the VM has exited.
11. `registers` - General-purpose MIPS32 registers. Each register is a 32-bit value.
The state is represented by packing the above fields, in order, into a 226-byte buffer.
## Memory
Memory is represented as a binary merkle tree.
The tree has a fixed-depth of 27 levels, with leaf values of 32 bytes each.
This spans the full 32-bit address space, where each leaf contains the memory at that part of the tree.
The state `memRoot` represents the merkle root of the tree, reflecting the effects of memory writes.
As a result of this memory representation, all memory operations are 4-byte aligned.
Memory access doesn't require any privileges. An instruction step can access any memory
location as the entire address space is unprotected.
### Heap
FPVM state contains a `heap` that tracks the base address of the most recent memory allocation.
Heap pages are bump allocated at the page boundary, per `mmap` syscall. The page size is 4096.
The FPVM has a fixed program break at `0x40000000`. However, the FPVM is permitted to extend the
heap beyond this limit via mmap syscalls.
For simplicity, there are no memory protections against "heap overruns" against other memory segments.
Such VM steps are still considered valid state transitions.
Specification of memory mappings is outside the scope of this document as it is irrelevant to
the VM state. FPVM implementers may refer to the Linux/MIPS kernel for inspiration.
## Delay Slots
The post-state of a step updates the `nextPC`, indicating the instruction following the `pc`.
However, in the case of where a branch instruction is being stepped, the `nextPC` post-state is
set to the branch target. And the `pc` post-state set to the branch delay slot as usual.
A VM state transition is invalid whenever the current instruction is a delay slot that is filled
with jump or branch type instruction.
That is, where $nextPC \neq pc + 4$ while stepping on a jump/branch instruction.
Otherwise, there would be two consecutive delay slots. While this is considered "undefined"
behavior in typical MIPS implementations, FPVM must raise an exception when stepping on such states.
## Syscalls
Syscalls work similar to [Linux/MIPS](https://www.linux-mips.org/wiki/Syscall), including the
syscall calling conventions and general syscall handling behavior.
However, the FPVM supports a subset of Linux/MIPS syscalls with slightly different behaviors.
The following table list summarizes the supported syscalls and their behaviors.
| $v0 | system call | $a0 | $a1 | $a2 | Effect |
| -- | -- | -- | -- | -- | -- |
| 4090 | mmap | uint32 addr | uint32 len | | Allocates a page from the heap. See [heap](#heap) for details. |
| 4045 | brk | | | | Returns a fixed address for the program break at `0x40000000` |
| 4120 | clone | | | | Returns 1 |
| 4246 | exit_group | uint8 exit_code | | | Sets the Exited and ExitCode states to `true` and `$a0` respectively. |
| 4003 | read | uint32 fd | char *buf | uint32 count | Similar behavior as Linux/MIPS with support for unaligned reads. See [I/O](#io) for more details. |
| 4004 | write | uint32 fd | char *buf | uint32 count | Similar behavior as Linux/MIPS with support for unaligned writes. See [I/O](#io) for more details. |
| 4055 | fcntl | uint32 fd | int32 cmd | | Similar behavior as Linux/MIPS. Only the `F_GETFL` (3) cmd is supported. Sets errno to `0x16` for all other commands |
For all of the above syscalls, an error is indicated by setting the return register (`$v0`) to
`0xFFFFFFFF` (-1) and `errno` (`$a3`) is set accordingly.
For unsupported syscalls, the VM must do nothing except to zero out the syscall return (`$v0`)
and errno (`$a3`) registers.
Note that the above syscalls have identical syscall numbers and ABIs as Linux/MIPS.
## I/O
The VM does not support Linux open(2). However, the VM can read from and write to a predefined set of file descriptors.
| Name | File descriptor | Description |
| ---- | --------------- | ----------- |
| stdin | 0 | read-only standard input stream. |
| stdout | 1 | write-only standaard output stream. |
| stderr | 2 | write-only standard error stream. |
| hint response | 3 | read-only. Used to read the status of [pre-image hinting](./fault-proof.md#hinting). |
| hint request | 4 | write-only. Used to provide [pre-image hints](./fault-proof.md#hinting) |
| pre-image response | 5 | read-only. Used to [read pre-images](./fault-proof.md#pre-image-communication). |
| pre-image request | 6 | write-only. Used to [request pre-images](./fault-proof.md#pre-image-communication). |
Syscalls referencing unnkown file descriptors fail with an `EBADF` errno as done on Linux.
Writing to and reading from standard output, input and error streams have no effect on the FPVM state.
FPVM implementations may use them for debugging purposes as long as I/O is stateless.
All I/O operations are restricted to a maximum of 4 bytes per operation.
Any read or write syscall request exceeding this limit will be truncated to 4 bytes.
Consequently, the return value of read/write syscalls is at most 4, indicating the actual number of bytes read/written.
### Standard Streams
Writing to stderr/stdout standard stream always succeeds with the write count input returned,
effectively continuing execution without writing work.
Reading from stdin has no effect other than to return zero and errno set to 0, signalling that there is no input.
### Hint Communication
Hint requests and responses have no effect on the VM state other than setting the `$v0` return
register to the requested read/write count.
VM implementations may utilize hints to setup subsequent pre-image requests.
### Pre-image Communication
The `preimageKey` and `preimageOffset` state are updated via read/write syscalls to the pre-image
read and write file descriptors (see [I/O](#io)).
The `preimageKey` buffers the stream of bytes written to the pre-image write fd.
The `preimageKey` buffer is shifted to accomodate new bytes written to the end of it.
A write also resets the `preimageOffset` to 0, indicating the intent to read a new pre-image.
When handling pre-image reads, the `preimageKey` is used to lookup the pre-image data from an Oracle.
A max 4-byte chunk of the pre-image at the `preimageOffset` is read to the specified address.
Each read operation increases the `preimageOffset` by the number of bytes requested
(truncated to 4 bytes and subject to alignment contraints).
#### Pre-image I/O Alignment
As mentioned earlier in [memory](#memory), all memory operations are 4-byte aligned.
Since pre-image I/O occurs on memory, all pre-image I/O operations must strictly adhere to alignment boundaries.
This means the start and end of a read/write operation must fall within the same alignment boundary.
If an operation were to violate this, the input `count` of the read/write syscall must be
truncated such that the effective address of the last byte read/writtten matches the input effective address.
The VM must read/write the maximum amount of bytes possible without crossing the input adress alignment boundary.
For example, the effect of a write request for a 3-byte aligned buffer must be exactly 3 bytes.
If the buffer is misaligned, then the VM may write less than 3 bytes depending on the size of the misalignment.
## Exceptions
The FPVM may raise an exception rather than output a post-state to signal an invalid state
transition. Nominally, the FPVM must raise an exception in at least the following cases:
- Invalid instruction (either via an invalid opcode or an instruction referencing registers
outside the general purpose registers).
- Pre-image read at an offset larger than the size of the pre-image.
- Delay slot contains branch/jump instruction types.
VM implementations may raise an exception in other cases that is specific to the implementation.
For example, an on-chain FPVM that relies on pre-supplied merkle proofs for memory access may
raise an exception if the supplied merkle proof doees not match the pre-state `memRoot`.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment