Full Code of 0xsequence/wallet-contracts for AI

master 09c54e74c280 cached
169 files
625.7 KB
179.1k tokens
131 symbols
1 requests
Download .txt
Showing preview only (673K chars total). Download the full file or copy to clipboard to get everything.
Repository: 0xsequence/wallet-contracts
Branch: master
Commit: 09c54e74c280
Files: 169
Total size: 625.7 KB

Directory structure:
gitextract_1y31azvd/

├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .github/
│   ├── actions/
│   │   └── install-dependencies/
│   │       └── action.yml
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .gitmodules
├── .husky/
│   └── pre-commit
├── .prettierrc
├── .solcover.js
├── .solhint.json
├── LICENSE
├── README.md
├── audits/
│   └── v1/
│       └── Consensys_Diligence.md
├── config/
│   └── PROD.env.sample
├── contracts/
│   ├── Factory.sol
│   ├── Wallet.sol
│   ├── hooks/
│   │   ├── WalletProxyHook.sol
│   │   └── interfaces/
│   │       └── IWalletProxy.sol
│   ├── interfaces/
│   │   ├── IERC1271Wallet.sol
│   │   ├── receivers/
│   │   │   ├── IERC1155Receiver.sol
│   │   │   ├── IERC223Receiver.sol
│   │   │   ├── IERC721Receiver.sol
│   │   │   └── IERC777Receiver.sol
│   │   └── tokens/
│   │       ├── IERC1155.sol
│   │       ├── IERC20.sol
│   │       └── IERC721.sol
│   ├── mocks/
│   │   ├── AlwaysRevertMock.sol
│   │   ├── CallReceiverMock.sol
│   │   ├── DelegateCallMock.sol
│   │   ├── ERC1155Mock.sol
│   │   ├── ERC165CheckerMock.sol
│   │   ├── ERC20Mock.sol
│   │   ├── ERC721Mock.sol
│   │   ├── GasBurnerMock.sol
│   │   ├── HookCallerMock.sol
│   │   ├── HookMock.sol
│   │   ├── LibBytesImpl.sol
│   │   ├── LibBytesPointerImpl.sol
│   │   ├── LibStringImp.sol
│   │   └── ModuleMock.sol
│   ├── modules/
│   │   ├── GuestModule.sol
│   │   ├── MainModule.sol
│   │   ├── MainModuleGasEstimation.sol
│   │   ├── MainModuleUpgradable.sol
│   │   ├── commons/
│   │   │   ├── Implementation.sol
│   │   │   ├── ModuleAuth.sol
│   │   │   ├── ModuleAuthConvenience.sol
│   │   │   ├── ModuleAuthFixed.sol
│   │   │   ├── ModuleAuthUpgradable.sol
│   │   │   ├── ModuleCalls.sol
│   │   │   ├── ModuleCreator.sol
│   │   │   ├── ModuleERC165.sol
│   │   │   ├── ModuleERC5719.sol
│   │   │   ├── ModuleExtraAuth.sol
│   │   │   ├── ModuleHooks.sol
│   │   │   ├── ModuleIPFS.sol
│   │   │   ├── ModuleNonce.sol
│   │   │   ├── ModuleOnlyDelegatecall.sol
│   │   │   ├── ModuleSelfAuth.sol
│   │   │   ├── ModuleStorage.sol
│   │   │   ├── ModuleUpdate.sol
│   │   │   ├── gas-estimation/
│   │   │   │   ├── ModuleIgnoreAuthUpgradable.sol
│   │   │   │   └── ModuleIgnoreNonceCalls.sol
│   │   │   ├── interfaces/
│   │   │   │   ├── IModuleAuth.sol
│   │   │   │   ├── IModuleAuthUpgradable.sol
│   │   │   │   ├── IModuleCalls.sol
│   │   │   │   ├── IModuleCreator.sol
│   │   │   │   ├── IModuleHooks.sol
│   │   │   │   └── IModuleUpdate.sol
│   │   │   └── submodules/
│   │   │       ├── auth/
│   │   │       │   ├── SequenceBaseSig.sol
│   │   │       │   ├── SequenceChainedSig.sol
│   │   │       │   ├── SequenceDynamicSig.sol
│   │   │       │   └── SequenceNoChainIdSig.sol
│   │   │       └── nonce/
│   │   │           └── SubModuleNonce.sol
│   │   └── utils/
│   │       ├── GasEstimator.sol
│   │       ├── MultiCallUtils.sol
│   │       ├── RequireUtils.sol
│   │       └── SequenceUtils.sol
│   ├── trust/
│   │   ├── Trust.sol
│   │   └── TrustFactory.sol
│   └── utils/
│       ├── LibAddress.sol
│       ├── LibBytes.sol
│       ├── LibBytesPointer.sol
│       ├── LibOptim.sol
│       ├── LibString.sol
│       └── SignatureValidator.sol
├── foundry.toml
├── foundry_test/
│   ├── base/
│   │   └── AdvTest.sol
│   ├── hooks/
│   │   └── WalletProxyHook.t.sol
│   ├── modules/
│   │   ├── commons/
│   │   │   ├── Implementation.t.sol
│   │   │   ├── ModuleCalls.t.sol
│   │   │   ├── ModuleERC5719.t.sol
│   │   │   ├── ModuleExtraAuth.t.sol
│   │   │   ├── ModuleIPFS.t.sol
│   │   │   ├── ModuleStorage.t.sol
│   │   │   └── submodules/
│   │   │       ├── auth/
│   │   │       │   ├── SequenceBaseSig.t.sol
│   │   │       │   ├── SequenceChainedSig.t.sol
│   │   │       │   ├── SequenceDynamicSig.t.sol
│   │   │       │   └── SequenceNoChainIdSig.t.sol
│   │   │       └── nonce/
│   │   │           └── SubModuleNonce.t.sol
│   │   └── utils/
│   │       ├── L2CompressorEncoder.sol
│   │       ├── L2CompressorHuff.t.sol
│   │       ├── L2CompressorHuffReadExecute.sol
│   │       ├── L2CompressorHuffReadFlag.t.sol
│   │       ├── L2CompressorHuffReadNonce.sol
│   │       ├── L2CompressorHuffReadTx.t.sol
│   │       ├── L2CompressorHuffReadTxs.t.sol
│   │       └── RequireUtils.t.sol
│   ├── trust/
│   │   ├── Trust.t.sol
│   │   └── TrustFactory.t.sol
│   └── utils/
│       ├── LibAddress.t.sol
│       ├── LibBytes.t.sol
│       ├── LibBytesPointer.t.sol
│       ├── LibOptim.t.sol
│       └── SignatureValidator.t.sol
├── funding.json
├── hardhat.config.ts
├── networks/
│   ├── arbitrum.json
│   ├── arbitrumGoerli.json
│   ├── arbitrumNova.json
│   ├── avalanche.json
│   ├── avalancheFuji.json
│   ├── bnb.json
│   ├── bnbTestnet.json
│   ├── gnosis.json
│   ├── goerli.json
│   ├── hardhat.json
│   ├── mainnet.json
│   ├── mumbai.json
│   ├── optimism.json
│   ├── polygon.json
│   └── polygonZkevm.json
├── package.json
├── remappings.txt
├── run_huff_tests.sh
├── src/
│   ├── Errors.huff
│   ├── L2Compressor.huff
│   ├── L2CompressorLib.huff
│   └── imps/
│       ├── L2CompressorImps.huff
│       ├── L2CompressorReadExecute.huff
│       ├── L2CompressorReadFlag.huff
│       ├── L2CompressorReadNonce.huff
│       ├── L2CompressorReadTx.huff
│       └── L2CompressorReadTxs.huff
├── test/
│   ├── ChainedSignatures.spec.ts
│   ├── ERC165.spec.ts
│   ├── Factory.spec.ts
│   ├── GasEstimation.spec.ts
│   ├── GuestModule.spec.ts
│   ├── LibBytes.spec.ts
│   ├── LibString.spec.ts
│   ├── MainModule.bench.ts
│   ├── MainModule.spec.ts
│   ├── MerkleSignatures.spec.ts
│   ├── MultiCallUtils.spec.ts
│   └── utils/
│       ├── contracts.ts
│       ├── imposter.ts
│       ├── index.ts
│       ├── sequence.ts
│       └── wallet.ts
├── tsconfig.json
├── typings/
│   ├── chai-bignumber.d.ts
│   ├── chai-bn.ts
│   └── truffle.d.ts
└── utils/
    ├── benchmarker.ts
    ├── config-loader.ts
    ├── deploy-contracts.ts
    └── workers/
        └── bench-worker.ts

================================================
FILE CONTENTS
================================================

================================================
FILE: .eslintignore
================================================
.eslintrc.js
node_modules
src/gen


================================================
FILE: .eslintrc.js
================================================
const { off } = require("process")

module.exports = {
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 2018,
    sourceType: 'module'
  },

  extends: [
    'plugin:@typescript-eslint/recommended',
    'plugin:import/errors',
    'plugin:import/warnings',
    'plugin:import/typescript',
    'prettier'
  ],

  rules: {
    '@typescript-eslint/no-unused-vars': 'off',
    '@typescript-eslint/no-explicit-any': 'off',
    '@typescript-eslint/no-non-null-assertion': 'off',
    '@typescript-eslint/explicit-module-boundary-types': 'off',
    '@typescript-eslint/ban-types': 'off',
    '@typescript-eslint/ban-ts-comment': 'off',
    '@typescript-eslint/no-empty-function': 'off',
    '@typescript-eslint/no-inferrable-types': 'off',
    '@typescript-eslint/no-var-requires': 'off',
    '@typescript-eslint/no-non-null-asserted-optional-chain': 'off',

    'prefer-spread': 'off',
    'prefer-const': 'off',

    'import/no-unresolved': 'off',
    // 'import/no-default-export': 2,
    'import/no-named-as-default-member': 'off',

  }
}


================================================
FILE: .gitattributes
================================================
*.sol linguist-language=Solidity


================================================
FILE: .github/actions/install-dependencies/action.yml
================================================
name: Setup Node and PNPM dependencies

runs:
  using: 'composite'

  steps:
    - name: Setup Node
      uses: actions/setup-node@v4
      with:
        node-version: 20

    - name: Setup PNPM
      uses: pnpm/action-setup@v3
      with:
        version: 9
        run_install: false

    - name: Get pnpm store directory
      id: pnpm-cache
      shell: bash
      run: |
        echo "STORE_PATH=$(pnpm store path)" >> $GITHUB_OUTPUT

    - name: Setup pnpm cache
      uses: actions/cache@v4
      with:
        path: |
          ${{ steps.pnpm-cache.outputs.STORE_PATH }}
        key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
        restore-keys: |
          ${{ runner.os }}-pnpm-store-

    - name: Install dependencies
      shell: bash
      run: pnpm install --frozen-lockfile
      if: ${{ steps.pnpm-cache.outputs.cache-hit != 'true' }}


================================================
FILE: .github/workflows/ci.yml
================================================
on: [push]

name: ci

jobs:
  benchmark:
    name: Benchmark
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/install-dependencies
      - run: pnpm build
      - run: pnpm benchmark

  lint-ts:
    name: Typescript lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/install-dependencies
      - run: pnpm lint:ts

  lint-sol:
    name: Solidity lint
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/install-dependencies
      - run: pnpm lint:sol

  test:
    name: Test contracts
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/install-dependencies
      - run: pnpm build
      - run: pnpm test

  coverage:
    name: Coverage
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: ./.github/actions/install-dependencies
      - run: pnpm coverage || true
      - name: Coveralls
        uses: coverallsapp/github-action@master
        with:
          github-token: ${{ secrets.GITHUB_TOKEN }}

  huff-tests:
    name: Huff tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install Huff
        uses: huff-language/huff-toolchain@v3
        with:
          version: nightly

      - name: Run tests
        run: bash ./run_huff_tests.sh

  foundry-tests:
    name: Foundry tests
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install Foundry
        uses: foundry-rs/foundry-toolchain@v1
        with:
          version: nightly

      - name: Install Huff
        uses: huff-language/huff-toolchain@v3
        with:
          version: nightly

      - name: Run tests
        run: FOUNDRY_FUZZ_RUNS=2048 MAX_ARRAY_LEN=32 forge test -vvv

  foundry-tests-long-arrays:
    name: Foundry tests (long arrays)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          submodules: recursive

      - name: Install Foundry
        uses: foundry-rs/foundry-toolchain@v1
        with:
          version: nightly

      - name: Install Huff
        uses: huff-language/huff-toolchain@v3
        with:
          version: nightly

      - name: Run tests
        run: FOUNDRY_FUZZ_RUNS=1024 forge test -vvv


================================================
FILE: .gitignore
================================================
.vscode
.devcontainer
node_modules/

npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*

*.js.map
build
coverage
coverage.json

config/*.env

artifacts
foundry_artifacts

cache
gen


================================================
FILE: .gitmodules
================================================
[submodule "lib/forge-std"]
	path = lib/forge-std
	url = https://github.com/foundry-rs/forge-std
[submodule "lib/foundry-huff"]
	path = lib/foundry-huff
	url = https://github.com/huff-language/foundry-huff

================================================
FILE: .husky/pre-commit
================================================
pnpm test


================================================
FILE: .prettierrc
================================================
{
  "tabWidth": 2,
  "useTabs": false,
  "semi": false,
  "singleQuote": true,
  "trailingComma": "none",
  "arrowParens": "avoid",
  "printWidth": 130
}


================================================
FILE: .solcover.js
================================================
module.exports = {
  skipFiles: ['mocks', 'migrations']
}


================================================
FILE: .solhint.json
================================================
{
  "extends": "solhint:recommended",
  "rules": {
    "quotes": "off",
    "const-name-snakecase": "off",
    "contract-name-camelcase": "off",
    "event-name-camelcase": "off",
    "func-name-mixedcase": "off",
    "func-param-name-mixedcase": "off",
    "modifier-name-mixedcase": "off",
    "private-vars-leading-underscore": "off",
    "use-forbidden-name": "off",
    "var-name-mixedcase": "off",
    "func-order": "off",
    "imports-on-top": "off",
    "ordering": "off",
    "no-global-import": "off",
    "no-unused-vars": "error",
    "not-rely-on-time": "off",
    "no-inline-assembly": "off",
    "visibility-modifier-order": "off",
    "compiler-version": ["error", "0.8.18"],
    "func-visibility": ["warn", {"ignoreConstructors":true}],
    "reason-string": ["warn", {"maxLength": 96}]
  }
}


================================================
FILE: LICENSE
================================================
   Copyright (c) 2017-present Horizon Blockchain Games Inc.

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


   ------------------------------------------------------------------------


                                 Apache License
                           Version 2.0, January 2004
                        http://www.apache.org/licenses/

   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION

   1. Definitions.

      "License" shall mean the terms and conditions for use, reproduction,
      and distribution as defined by Sections 1 through 9 of this document.

      "Licensor" shall mean the copyright owner or entity authorized by
      the copyright owner that is granting the License.

      "Legal Entity" shall mean the union of the acting entity and all
      other entities that control, are controlled by, or are under common
      control with that entity. For the purposes of this definition,
      "control" means (i) the power, direct or indirect, to cause the
      direction or management of such entity, whether by contract or
      otherwise, or (ii) ownership of fifty percent (50%) or more of the
      outstanding shares, or (iii) beneficial ownership of such entity.

      "You" (or "Your") shall mean an individual or Legal Entity
      exercising permissions granted by this License.

      "Source" form shall mean the preferred form for making modifications,
      including but not limited to software source code, documentation
      source, and configuration files.

      "Object" form shall mean any form resulting from mechanical
      transformation or translation of a Source form, including but
      not limited to compiled object code, generated documentation,
      and conversions to other media types.

      "Work" shall mean the work of authorship, whether in Source or
      Object form, made available under the License, as indicated by a
      copyright notice that is included in or attached to the work
      (an example is provided in the Appendix below).

      "Derivative Works" shall mean any work, whether in Source or Object
      form, that is based on (or derived from) the Work and for which the
      editorial revisions, annotations, elaborations, or other modifications
      represent, as a whole, an original work of authorship. For the purposes
      of this License, Derivative Works shall not include works that remain
      separable from, or merely link (or bind by name) to the interfaces of,
      the Work and Derivative Works thereof.

      "Contribution" shall mean any work of authorship, including
      the original version of the Work and any modifications or additions
      to that Work or Derivative Works thereof, that is intentionally
      submitted to Licensor for inclusion in the Work by the copyright owner
      or by an individual or Legal Entity authorized to submit on behalf of
      the copyright owner. For the purposes of this definition, "submitted"
      means any form of electronic, verbal, or written communication sent
      to the Licensor or its representatives, including but not limited to
      communication on electronic mailing lists, source code control systems,
      and issue tracking systems that are managed by, or on behalf of, the
      Licensor for the purpose of discussing and improving the Work, but
      excluding communication that is conspicuously marked or otherwise
      designated in writing by the copyright owner as "Not a Contribution."

      "Contributor" shall mean Licensor and any individual or Legal Entity
      on behalf of whom a Contribution has been received by Licensor and
      subsequently incorporated within the Work.

   2. Grant of Copyright License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      copyright license to reproduce, prepare Derivative Works of,
      publicly display, publicly perform, sublicense, and distribute the
      Work and such Derivative Works in Source or Object form.

   3. Grant of Patent License. Subject to the terms and conditions of
      this License, each Contributor hereby grants to You a perpetual,
      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
      (except as stated in this section) patent license to make, have made,
      use, offer to sell, sell, import, and otherwise transfer the Work,
      where such license applies only to those patent claims licensable
      by such Contributor that are necessarily infringed by their
      Contribution(s) alone or by combination of their Contribution(s)
      with the Work to which such Contribution(s) was submitted. If You
      institute patent litigation against any entity (including a
      cross-claim or counterclaim in a lawsuit) alleging that the Work
      or a Contribution incorporated within the Work constitutes direct
      or contributory patent infringement, then any patent licenses
      granted to You under this License for that Work shall terminate
      as of the date such litigation is filed.

   4. Redistribution. You may reproduce and distribute copies of the
      Work or Derivative Works thereof in any medium, with or without
      modifications, and in Source or Object form, provided that You
      meet the following conditions:

      (a) You must give any other recipients of the Work or
          Derivative Works a copy of this License; and

      (b) You must cause any modified files to carry prominent notices
          stating that You changed the files; and

      (c) You must retain, in the Source form of any Derivative Works
          that You distribute, all copyright, patent, trademark, and
          attribution notices from the Source form of the Work,
          excluding those notices that do not pertain to any part of
          the Derivative Works; and

      (d) If the Work includes a "NOTICE" text file as part of its
          distribution, then any Derivative Works that You distribute must
          include a readable copy of the attribution notices contained
          within such NOTICE file, excluding those notices that do not
          pertain to any part of the Derivative Works, in at least one
          of the following places: within a NOTICE text file distributed
          as part of the Derivative Works; within the Source form or
          documentation, if provided along with the Derivative Works; or,
          within a display generated by the Derivative Works, if and
          wherever such third-party notices normally appear. The contents
          of the NOTICE file are for informational purposes only and
          do not modify the License. You may add Your own attribution
          notices within Derivative Works that You distribute, alongside
          or as an addendum to the NOTICE text from the Work, provided
          that such additional attribution notices cannot be construed
          as modifying the License.

      You may add Your own copyright statement to Your modifications and
      may provide additional or different license terms and conditions
      for use, reproduction, or distribution of Your modifications, or
      for any such Derivative Works as a whole, provided Your use,
      reproduction, and distribution of the Work otherwise complies with
      the conditions stated in this License.

   5. Submission of Contributions. Unless You explicitly state otherwise,
      any Contribution intentionally submitted for inclusion in the Work
      by You to the Licensor shall be under the terms and conditions of
      this License, without any additional terms or conditions.
      Notwithstanding the above, nothing herein shall supersede or modify
      the terms of any separate license agreement you may have executed
      with Licensor regarding such Contributions.

   6. Trademarks. This License does not grant permission to use the trade
      names, trademarks, service marks, or product names of the Licensor,
      except as required for reasonable and customary use in describing the
      origin of the Work and reproducing the content of the NOTICE file.

   7. Disclaimer of Warranty. Unless required by applicable law or
      agreed to in writing, Licensor provides the Work (and each
      Contributor provides its Contributions) on an "AS IS" BASIS,
      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
      implied, including, without limitation, any warranties or conditions
      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
      PARTICULAR PURPOSE. You are solely responsible for determining the
      appropriateness of using or redistributing the Work and assume any
      risks associated with Your exercise of permissions under this License.

   8. Limitation of Liability. In no event and under no legal theory,
      whether in tort (including negligence), contract, or otherwise,
      unless required by applicable law (such as deliberate and grossly
      negligent acts) or agreed to in writing, shall any Contributor be
      liable to You for damages, including any direct, indirect, special,
      incidental, or consequential damages of any character arising as a
      result of this License or out of the use or inability to use the
      Work (including but not limited to damages for loss of goodwill,
      work stoppage, computer failure or malfunction, or any and all
      other commercial damages or losses), even if such Contributor
      has been advised of the possibility of such damages.

   9. Accepting Warranty or Additional Liability. While redistributing
      the Work or Derivative Works thereof, You may choose to offer,
      and charge a fee for, acceptance of support, warranty, indemnity,
      or other liability obligations and/or rights consistent with this
      License. However, in accepting such obligations, You may act only
      on Your own behalf and on Your sole responsibility, not on behalf
      of any other Contributor, and only if You agree to indemnify,
      defend, and hold each Contributor harmless for any liability
      incurred by, or claims asserted against, such Contributor by reason
      of your accepting any such warranty or additional liability.

   END OF TERMS AND CONDITIONS

   APPENDIX: How to apply the Apache License to your work.

      To apply the Apache License to your work, attach the following
      boilerplate notice, with the fields enclosed by brackets "[]"
      replaced with your own identifying information. (Don't include
      the brackets!)  The text should be enclosed in the appropriate
      comment syntax for the file format. We also recommend that a
      file or class name and description of purpose be included on the
      same "printed page" as the copyright notice for easier
      identification within third-party archives.

   Copyright [yyyy] [name of copyright owner]

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.


================================================
FILE: README.md
================================================
# Sequence Smart Wallet Contracts

Ethereum contracts for the Sequence Smart Wallet at [https://sequence.app](https://sequence.app).

For more information, visit [https://sequence.build](https://sequence.build)

## Usage

Please visit [https://sequence.app](https://sequence.app) to access the Sequence Wallet via your Web Browser, or
download "Sequence Wallet" from the respective Apple/Google stores.

You may also access, interface, or develop your own Sequence Wallet via [sequence.js](https://github.com/0xsequence/sequence.js). The
sequence.js library offers a full open source library to interact, create, deploy and manage a Sequence Smart Wallet Account,
as defined by the contracts in this repository. Also see [go-sequence](https://github.com/0xsequence/go-sequence) for an implementation
in Go.

## Connecting your Dapp with Sequence Wallet

If you wish to use Sequence Wallet in your Dapp, simply use [sequence.js](https://github.com/0xsequence/sequence.js). Sequence.js
is an Ethereum client library built on [ethers.js](https://github.com/ethers-io/ethers.js), that provides an additional
Sequence Smart Wallet Signer.

Please refer to the [sequence.js](https://github.com/0xsequence/sequence.js) repository for usage instructions.

# Developing a Custom Wallet UI for Sequence (Advanced!)

If you wish to use the Sequence Wallet Contracts `@0xsequence/wallet-contracts` directly:

1. Install the contracts: `pnpm add @0xsequence/wallet-contracts` or `npm install @0xsequence/wallet-contracts`
2. Install the Sequence Wallet libraries: `pnpm add @0xsequence/wallet` or `npm install @0xsequence/wallet`. You can view the source,
   of the [wallet libraries](https://github.com/0xsequence/sequence.js/tree/master/packages/wallet), and review the
   [Sequence tests](https://github.com/0xsequence/sequence.js/tree/master/packages/0xsequence) for sample usage.

**NOTE:** this integration is only needed if you want low-level access to the Sequence Wallet contracts, such as if you'd building
your own custom wallet, or perhaps a CLI tool for managing your wallet.

## Security Review

`@0xsequence/wallet-contracts` has been audited by independent parties.

### V2 Audits

- [Consensys Diligence](https://github.com/0xsequence/wallet-contracts/blob/master/audits/v2/consensys-horizon-sequence-wallet-audit-2023-02.pdf) - February 2023
- [Zellic](https://github.com/0xsequence/wallet-contracts/raw/master/audits/Quantstamp_Arcadeum_Report_Final.pdf) - March 2023

### V1 Audits

- [Consensys Diligence](https://github.com/0xsequence/wallet-contracts/blob/master/audits/v1/Consensys_Diligence.md) - May 2020
- [Quantstamp - initial audit](https://github.com/0xsequence/wallet-contracts/raw/master/audits/v1/Quantstamp_Arcadeum_Report_Final.pdf) - July 2020
- [Quantstamp - audit of new capability, nested Sequence signers](https://github.com/0xsequence/wallet-contracts/raw/master/audits/v1/sequence_quantstamp_audit_feb_2021.pdf) - February 2021

## License

Copyright (c) 2017-present [Horizon Blockchain Games Inc](https://horizon.io).

Licensed under [Apache-2.0](https://github.com/0xsequence/erc-1155/blob/master/LICENSE)


================================================
FILE: audits/v1/Consensys_Diligence.md
================================================
# Consensys Diligence report May 2020

[View full report](https://diligence.consensys.net/audits/private/cnhjwtpa-horizon-wallet/)

Please note, Sequence Wallet was formerly known as "Arcadeum Wallet". Any references of "Arcadeum"
are synonymous with "Sequence", and this repository.



================================================
FILE: config/PROD.env.sample
================================================
ETH_MNEMONIC=""
INFURA_API_KEY=""
ETHERSCAN=""


================================================
FILE: contracts/Factory.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./Wallet.sol";


contract Factory {
  error DeployFailed(address _mainModule, bytes32 _salt);

  /**
   * @notice Will deploy a new wallet instance
   * @param _mainModule Address of the main module to be used by the wallet
   * @param _salt Salt used to generate the wallet, which is the imageHash
   *       of the wallet's configuration.
   * @dev It is recommended to not have more than 200 signers as opcode repricing
   *      could make transactions impossible to execute as all the signers must be
   *      passed for each transaction.
   */
  function deploy(address _mainModule, bytes32 _salt) public payable returns (address _contract) {
    bytes memory code = abi.encodePacked(Wallet.creationCode, uint256(uint160(_mainModule)));
    assembly { _contract := create2(callvalue(), add(code, 32), mload(code), _salt) }
    if (_contract == address(0)) revert DeployFailed(_mainModule, _salt);
  }
}


================================================
FILE: contracts/Wallet.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

/**
    Minimal upgradeable proxy implementation, delegates all calls to the address
    defined by the storage slot matching the wallet address.

    Inspired by EIP-1167 Implementation (https://eips.ethereum.org/EIPS/eip-1167)

    deployed code:

        0x00    0x36         0x36      CALLDATASIZE      cds
        0x01    0x3d         0x3d      RETURNDATASIZE    0 cds
        0x02    0x3d         0x3d      RETURNDATASIZE    0 0 cds
        0x03    0x37         0x37      CALLDATACOPY
        0x04    0x3d         0x3d      RETURNDATASIZE    0
        0x05    0x3d         0x3d      RETURNDATASIZE    0 0
        0x06    0x3d         0x3d      RETURNDATASIZE    0 0 0
        0x07    0x36         0x36      CALLDATASIZE      cds 0 0 0
        0x08    0x3d         0x3d      RETURNDATASIZE    0 cds 0 0 0
        0x09    0x30         0x30      ADDRESS           addr 0 cds 0 0 0
        0x0A    0x54         0x54      SLOAD             imp 0 cds 0 0 0
        0x0B    0x5a         0x5a      GAS               gas imp 0 cds 0 0 0
        0x0C    0xf4         0xf4      DELEGATECALL      suc 0
        0x0D    0x3d         0x3d      RETURNDATASIZE    rds suc 0
        0x0E    0x82         0x82      DUP3              0 rds suc 0
        0x0F    0x80         0x80      DUP1              0 0 rds suc 0
        0x10    0x3e         0x3e      RETURNDATACOPY    suc 0
        0x11    0x90         0x90      SWAP1             0 suc
        0x12    0x3d         0x3d      RETURNDATASIZE    rds 0 suc
        0x13    0x91         0x91      SWAP2             suc 0 rds
        0x14    0x60 0x18    0x6018    PUSH1             0x18 suc 0 rds
    /-- 0x16    0x57         0x57      JUMPI             0 rds
    |   0x17    0xfd         0xfd      REVERT
    \-> 0x18    0x5b         0x5b      JUMPDEST          0 rds
        0x19    0xf3         0xf3      RETURN

    flat deployed code: 0x363d3d373d3d3d363d30545af43d82803e903d91601857fd5bf3

    deploy function:

        0x00    0x60 0x3a    0x603a    PUSH1             0x3a
        0x02    0x60 0x0e    0x600e    PUSH1             0x0e 0x3a
        0x04    0x3d         0x3d      RETURNDATASIZE    0 0x0e 0x3a
        0x05    0x39         0x39      CODECOPY
        0x06    0x60 0x1a    0x601a    PUSH1             0x1a
        0x08    0x80         0x80      DUP1              0x1a 0x1a
        0x09    0x51         0x51      MLOAD             imp 0x1a
        0x0A    0x30         0x30      ADDRESS           addr imp 0x1a
        0x0B    0x55         0x55      SSTORE            0x1a
        0x0C    0x3d         0x3d      RETURNDATASIZE    0 0x1a
        0x0D    0xf3         0xf3      RETURN
        [...deployed code]

    flat deploy function: 0x603a600e3d39601a805130553df3363d3d373d3d3d363d30545af43d82803e903d91601857fd5bf3
*/
library Wallet {
  bytes internal constant creationCode = hex"603a600e3d39601a805130553df3363d3d373d3d3d363d30545af43d82803e903d91601857fd5bf3";
}


================================================
FILE: contracts/hooks/WalletProxyHook.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import {IWalletProxy} from './interfaces/IWalletProxy.sol';
import {Implementation} from '../modules/commons/Implementation.sol';

contract WalletProxyHook is IWalletProxy, Implementation {
  /// @inheritdoc IWalletProxy
  function PROXY_getImplementation() public view returns (address) {
    return _getImplementation();
  }
}


================================================
FILE: contracts/hooks/interfaces/IWalletProxy.sol
================================================
// Copyright Immutable Pty Ltd 2018 - 2023
// SPDX-License-Identifier: Apache 2.0
// https://github.com/immutable/contracts/blob/a04f7ecb8a79ad8f1b67f73f770e0545deb6cba2/contracts/allowlist/IWalletProxy.sol
pragma solidity 0.8.18;

// Interface to retrieve the implemention stored inside the Proxy contract
/// Interface for Passport Wallet's proxy contract.
interface IWalletProxy {
    // Returns the current implementation address used by the proxy contract
    // solhint-disable-next-line func-name-mixedcase
    function PROXY_getImplementation() external view returns (address);
}


================================================
FILE: contracts/interfaces/IERC1271Wallet.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


interface IERC1271Wallet {

  /**
   * @notice Verifies whether the provided signature is valid with respect to the provided data
   * @dev MUST return the correct magic value if the signature provided is valid for the provided data
   *   > The bytes4 magic value to return when signature is valid is 0x20c13b0b : bytes4(keccak256("isValidSignature(bytes,bytes)")
   *   > This function MAY modify Ethereum's state
   * @param _data       Arbitrary length data signed on the behalf of address(this)
   * @param _signature  Signature byte array associated with _data
   * @return magicValue Magic value 0x20c13b0b if the signature is valid and 0x0 otherwise
   */
  function isValidSignature(
    bytes calldata _data,
    bytes calldata _signature)
    external
    view
    returns (bytes4 magicValue);

  /**
   * @notice Verifies whether the provided signature is valid with respect to the provided hash
   * @dev MUST return the correct magic value if the signature provided is valid for the provided hash
   *   > The bytes4 magic value to return when signature is valid is 0x20c13b0b : bytes4(keccak256("isValidSignature(bytes,bytes)")
   *   > This function MAY modify Ethereum's state
   * @param _hash       keccak256 hash that was signed
   * @param _signature  Signature byte array associated with _data
   * @return magicValue Magic value 0x20c13b0b if the signature is valid and 0x0 otherwise
   */
  function isValidSignature(
    bytes32 _hash,
    bytes calldata _signature)
    external
    view
    returns (bytes4 magicValue);
}

================================================
FILE: contracts/interfaces/receivers/IERC1155Receiver.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


interface IERC1155Receiver {
  function onERC1155Received(address, address, uint256, uint256, bytes calldata) external returns (bytes4);
  function onERC1155BatchReceived(address, address, uint256[] calldata, uint256[] calldata, bytes calldata) external returns (bytes4);
}


================================================
FILE: contracts/interfaces/receivers/IERC223Receiver.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


interface IERC223Receiver {
  function tokenFallback(address, uint256, bytes calldata) external;
}


================================================
FILE: contracts/interfaces/receivers/IERC721Receiver.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


interface IERC721Receiver {
  function onERC721Received(address, address, uint256, bytes calldata) external returns (bytes4);
}


================================================
FILE: contracts/interfaces/receivers/IERC777Receiver.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

interface IERC777Receiver {
    function tokensReceived(address, address, address, uint256, bytes calldata, bytes calldata) external;
}


================================================
FILE: contracts/interfaces/tokens/IERC1155.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

interface IERC1155 {
  function balanceOf(address account, uint256 id) external view returns (uint256);
  function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids) external view returns (uint256[] memory);
  function setApprovalForAll(address operator, bool approved) external;
  function isApprovedForAll(address account, address operator) external view returns (bool);
  function safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes calldata data) external;
  function safeBatchTransferFrom(
    address from,
    address to,
    uint256[] calldata ids,
    uint256[] calldata amounts,
    bytes calldata data
  ) external;

  event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
  event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);
  event ApprovalForAll(address indexed account, address indexed operator, bool approved);
  event URI(string value, uint256 indexed id);
}


================================================
FILE: contracts/interfaces/tokens/IERC20.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

interface IERC20 {
  function totalSupply() external view returns (uint256);
  function balanceOf(address account) external view returns (uint256);
  function transfer(address recipient, uint256 amount) external returns (bool);
  function allowance(address owner, address spender) external view returns (uint256);
  function approve(address spender, uint256 amount) external returns (bool);
  function transferFrom(address sender, address recipient, uint256 amount) external returns (bool);

  event Transfer(address indexed from, address indexed to, uint256 value);
  event Approval(address indexed owner, address indexed spender, uint256 value);
}


================================================
FILE: contracts/interfaces/tokens/IERC721.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

interface IERC721 {
  function balanceOf(address owner) external view returns (uint256 balance);
  function ownerOf(uint256 tokenId) external view returns (address owner);
  function safeTransferFrom(address from, address to, uint256 tokenId) external;
  function transferFrom(address from, address to, uint256 tokenId) external;
  function approve(address to, uint256 tokenId) external;
  function getApproved(uint256 tokenId) external view returns (address operator);
  function setApprovalForAll(address operator, bool approved) external;
  function isApprovedForAll(address owner, address operator) external view returns (bool);
  function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

  event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
  event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
  event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
}


================================================
FILE: contracts/mocks/AlwaysRevertMock.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


contract AlwaysRevertMock {
  fallback() external payable {
    revert("AlwaysRevertMock#fallback: ALWAYS_REVERT");
  }
}


================================================
FILE: contracts/mocks/CallReceiverMock.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


contract CallReceiverMock {
  uint256 public lastValA;
  bytes public lastValB;

  bool revertFlag;

  constructor() payable { }

  function setRevertFlag(bool _revertFlag) external {
    revertFlag = _revertFlag;
  }

  function testCall(uint256 _valA, bytes calldata _valB) external payable {
    require(!revertFlag, "CallReceiverMock#testCall: REVERT_FLAG");

    lastValA = _valA;
    lastValB = _valB;
  }
}


================================================
FILE: contracts/mocks/DelegateCallMock.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


contract DelegateCallMock {
  event Readed(uint256 _val);

  uint256 private constant REVERT_SLOT = uint256(keccak256("revert-flag"));

  mapping(uint256 => uint256) private store;

  function setRevertFlag(bool _revertFlag) external {
    store[REVERT_SLOT] = _revertFlag ? 1 : 0;
  }

  function write(uint256 _key, uint256 _val) external {
    require(store[REVERT_SLOT] == 0, "DelegateCallMock#write: REVERT_FLAG");
    store[_key] = _val;
  }

  function read(uint256 _key) external {
    emit Readed(store[_key]);
  }
}


================================================
FILE: contracts/mocks/ERC1155Mock.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract ERC1155Mock {
  string public name = 'Mock ERC1155 Token';
  string public symbol = 'MERC1155';
  address public owner;

  mapping(uint256 => mapping(address => uint256)) public balances;
  mapping(address => mapping(address => bool)) public operatorApprovals;

  constructor() {
    owner = msg.sender;
  }

  modifier onlyOwner() {
    require(msg.sender == owner, 'Only owner can mint');
    _;
  }

  function balanceOf(address account, uint256 id) public view returns (uint256) {
    return balances[id][account];
  }

  function balanceOfBatch(address[] memory accounts, uint256[] memory ids) public view returns (uint256[] memory) {
    require(accounts.length == ids.length, 'Accounts and ids length mismatch');

    uint256[] memory batchBalances = new uint256[](accounts.length);
    for (uint256 i = 0; i < accounts.length; ++i) {
      batchBalances[i] = balances[ids[i]][accounts[i]];
    }
    return batchBalances;
  }

  function mint(address to, uint256 id, uint256 amount) public onlyOwner {
    require(to != address(0), 'Cannot mint to zero address');

    balances[id][to] += amount;
    emit TransferSingle(msg.sender, address(0), to, id, amount);
  }

  function safeTransferFrom(address from, address to, uint256 id, uint256 amount) public {
    require(from == msg.sender || isApprovedForAll(from, msg.sender), 'Not approved to transfer');

    require(balances[id][from] >= amount, 'Insufficient balance');
    balances[id][from] -= amount;
    balances[id][to] += amount;

    emit TransferSingle(msg.sender, from, to, id, amount);
  }

  function setApprovalForAll(address operator, bool approved) public {
    operatorApprovals[msg.sender][operator] = approved;
    emit ApprovalForAll(msg.sender, operator, approved);
  }

  function isApprovedForAll(address account, address operator) public view returns (bool) {
    return operatorApprovals[account][operator];
  }

  event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
  event ApprovalForAll(address indexed account, address indexed operator, bool approved);
}


================================================
FILE: contracts/mocks/ERC165CheckerMock.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


contract ERC165CheckerMock {
  bytes4 constant InvalidID = 0xffffffff;
  bytes4 constant ERC165ID = 0x01ffc9a7;

  function doesContractImplementInterface(address _contract, bytes4 _interfaceId) external view returns (bool) {
    uint256 success;
    uint256 result;

    (success, result) = noThrowCall(_contract, ERC165ID);
    if (success == 0 || result == 0) {
      return false;
    }

    (success, result) = noThrowCall(_contract, InvalidID);
    if (success == 0 || result != 0) {
      return false;
    }

    (success, result) = noThrowCall(_contract, _interfaceId);
    if (success == 1 && result == 1) {
      return true;
    }
    return false;
  }

  function noThrowCall(
    address _contract,
    bytes4 _interfaceId
  ) private view returns (
    uint256 success,
    uint256 result
  ) {
    bytes4 erc165ID = ERC165ID;

    assembly {
      let x := mload(0x40)               // Find empty storage location using "free memory pointer"
      mstore(x, erc165ID)                // Place signature at beginning of empty storage
      mstore(add(x, 0x04), _interfaceId) // Place first argument directly next to signature

      success := staticcall(
        30000,     // 30k gas
        _contract, // To addr
        x,         // Inputs are stored at location x
        0x24,      // Inputs are 36 bytes long
        x,         // Store output over input (saves space)
        0x20       // Outputs are 32 bytes long
      )

      result := mload(x)                 // Load the result
    }
  }
}


================================================
FILE: contracts/mocks/ERC20Mock.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract ERC20Mock {
  string public name = 'Mock ERC20 Token';
  string public symbol = 'MERC20';
  uint8 public decimals = 18;
  uint256 public totalSupply;
  mapping(address => uint256) public balances;
  mapping(address => mapping(address => uint256)) public allowances;

  constructor(uint256 initialSupply) {
    totalSupply = initialSupply;
    balances[msg.sender] = initialSupply;
  }

  function balanceOf(address account) public view returns (uint256) {
    return balances[account];
  }

  function transfer(address recipient, uint256 amount) public returns (bool) {
    require(balances[msg.sender] >= amount, 'Insufficient balance');
    balances[msg.sender] -= amount;
    balances[recipient] += amount;
    emit Transfer(msg.sender, recipient, amount);
    return true;
  }

  function allowance(address owner, address spender) public view returns (uint256) {
    return allowances[owner][spender];
  }

  function approve(address spender, uint256 amount) public returns (bool) {
    allowances[msg.sender][spender] = amount;
    emit Approval(msg.sender, spender, amount);
    return true;
  }

  function transferFrom(address sender, address recipient, uint256 amount) public returns (bool) {
    require(balances[sender] >= amount, 'Insufficient balance');
    require(allowances[sender][msg.sender] >= amount, 'Allowance exceeded');
    balances[sender] -= amount;
    balances[recipient] += amount;
    allowances[sender][msg.sender] -= amount;
    emit Transfer(sender, recipient, amount);
    return true;
  }

  event Transfer(address indexed from, address indexed to, uint256 value);
  event Approval(address indexed owner, address indexed spender, uint256 value);
}


================================================
FILE: contracts/mocks/ERC721Mock.sol
================================================
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.18;

contract ERC721Mock {
  string public name = 'Mock ERC721 Token';
  string public symbol = 'MERC721';
  uint256 public totalSupply;
  address public owner;

  mapping(address => uint256) public balances;
  mapping(uint256 => address) public owners;
  mapping(address => mapping(address => bool)) public operatorApprovals;
  mapping(uint256 => address) public tokenApprovals;

  constructor() {
    owner = msg.sender;
  }

  modifier onlyOwner() {
    require(msg.sender == owner, 'Only owner can mint');
    _;
  }

  function balanceOf(address _owner) public view returns (uint256) {
    return balances[_owner];
  }

  function ownerOf(uint256 tokenId) public view returns (address) {
    address tokenOwner = owners[tokenId];
    require(tokenOwner != address(0), 'Token does not exist');
    return tokenOwner;
  }

  function mint(address to, uint256 tokenId) public onlyOwner {
    require(to != address(0), 'Cannot mint to zero address');
    require(owners[tokenId] == address(0), 'Token already minted');

    owners[tokenId] = to;
    balances[to] += 1;
    totalSupply += 1;

    emit Transfer(address(0), to, tokenId);
  }

  function transferFrom(address from, address to, uint256 tokenId) public {
    require(ownerOf(tokenId) == from, 'Not the owner of the token');
    require(to != address(0), 'Cannot transfer to zero address');

    require(
      msg.sender == from || getApproved(tokenId) == msg.sender || isApprovedForAll(from, msg.sender),
      'Not approved to transfer'
    );

    balances[from] -= 1;
    balances[to] += 1;
    owners[tokenId] = to;

    emit Transfer(from, to, tokenId);
  }

  function approve(address to, uint256 tokenId) public {
    address tokenOwner = ownerOf(tokenId);
    require(to != tokenOwner, 'Cannot approve current owner');
    require(msg.sender == tokenOwner || isApprovedForAll(tokenOwner, msg.sender), 'Not approved');

    tokenApprovals[tokenId] = to;
    emit Approval(tokenOwner, to, tokenId);
  }

  function getApproved(uint256 tokenId) public view returns (address) {
    return tokenApprovals[tokenId];
  }

  function setApprovalForAll(address operator, bool approved) public {
    operatorApprovals[msg.sender][operator] = approved;
    emit ApprovalForAll(msg.sender, operator, approved);
  }

  function isApprovedForAll(address _owner, address operator) public view returns (bool) {
    return operatorApprovals[_owner][operator];
  }

  event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
  event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
  event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
}


================================================
FILE: contracts/mocks/GasBurnerMock.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


contract GasBurnerMock {
  event ProvidedGas(uint256 _val);

  function burnGas(uint256 _burn) external {
    emit ProvidedGas(gasleft());

    bytes32 stub;
    uint256 initial = gasleft();

    while (initial - gasleft() < _burn) {
      stub = keccak256(abi.encode(stub));
    }
  }
}


================================================
FILE: contracts/mocks/HookCallerMock.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "../interfaces/receivers/IERC1155Receiver.sol";
import "../interfaces/receivers/IERC721Receiver.sol";
import "../interfaces/receivers/IERC223Receiver.sol";

import "../interfaces/IERC1271Wallet.sol";


contract HookCallerMock {
  function callERC1155Received(address _addr) external {
    bytes4 result = IERC1155Receiver(_addr).onERC1155Received(
      address(this),
      msg.sender,
      1,
      2,
      msg.data
    );

    require(result == 0xf23a6e61, "HookCallerMock#callERC1155Received: INVALID_RETURN");
  }

  function callERC1155BatchReceived(address _addr) external {
    uint256[] memory ids = new uint256[](3);
    ids[0] = 1;
    ids[1] = 2;
    ids[2] = 3;

    uint256[] memory values = new uint256[](3);
    values[0] = 200;
    values[1] = 300;
    values[2] = 400;

    bytes4 result = IERC1155Receiver(_addr).onERC1155BatchReceived(
      address(this),
      msg.sender,
      ids,
      values,
      msg.data
    );

    require(result == 0xbc197c81, "HookCallerMock#callERC1155BatchReceived: INVALID_RETURN");
  }

  function callERC721Received(address _addr) external {
    bytes4 result = IERC721Receiver(_addr).onERC721Received(
      address(this),
      msg.sender,
      1,
      msg.data
    );

    require(result == 0x150b7a02, "HookCallerMock#callERC721Received: INVALID_RETURN");
  }

  function callERC223Received(address _addr) external {
    IERC223Receiver(_addr).tokenFallback(msg.sender, 1, msg.data);
  }

  function callERC1271isValidSignatureData(
    address _addr,
    bytes calldata _data,
    bytes calldata _signature
  ) external view {
    bytes4 result = IERC1271Wallet(_addr).isValidSignature(_data, _signature);
    require(result == 0x20c13b0b, "HookCallerMock#callERC1271isValidSignatureData: INVALID_RETURN");
  }

  function callERC1271isValidSignatureHash(
    address _addr,
    bytes32 _hash,
    bytes calldata _signature
  ) external view {
    bytes4 result = IERC1271Wallet(_addr).isValidSignature(_hash, _signature);
    require(result == 0x1626ba7e, "HookCallerMock#callERC1271isValidSignatureHash: INVALID_RETURN");
  }
}


================================================
FILE: contracts/mocks/HookMock.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


contract HookMock {
  function onHookMockCall(uint256 _num) external pure returns (uint256) {
    return _num * 2;
  }
}


================================================
FILE: contracts/mocks/LibBytesImpl.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "../utils/LibBytes.sol";


contract LibBytesImpl {
  using LibBytes for bytes;

  function readBytes32(
    bytes calldata data,
    uint256 index
  ) external pure returns (
    bytes32 a
  ) {
    return LibBytes.readBytes32(data, index);
  }

  function readUint8(
    bytes calldata data,
    uint256 index
  ) external pure returns (
    uint8 a
  ) {
    return LibBytes.readUint8(data, index);
  }

  function readUint32(
    bytes calldata data,
    uint256 index
  ) external pure returns (
    uint32 a
  ) {
    return LibBytes.readUint32(data, index);
  }
}


================================================
FILE: contracts/mocks/LibBytesPointerImpl.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "../utils/LibBytesPointer.sol";


contract LibBytesPointerImpl {
  using LibBytesPointer for bytes;

  function readFirstUint16(
    bytes calldata data
  ) external pure returns (
    uint16 a,
    uint256 newPointer
  ) {
    return LibBytesPointer.readFirstUint16(data);
  }

  function readUint16(
    bytes calldata data,
    uint256 index
  ) external pure returns (
    uint16 a,
    uint256 newPointer
  ) {
    return LibBytesPointer.readUint16(data, index);
  }

  function readUint24(
    bytes calldata data,
    uint256 index
  ) external pure returns (
    uint24 a,
    uint256 newPointer
  ) {
    return LibBytesPointer.readUint24(data, index);
  }

  function readUint64(
    bytes calldata data,
    uint256 index
  ) external pure returns (
    uint64 a,
    uint256 newPointer
  ) {
    return LibBytesPointer.readUint64(data, index);
  }
}


================================================
FILE: contracts/mocks/LibStringImp.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "../utils/LibString.sol";


contract LibStringImp {
  using LibString for string;

  function prefixBase32(string calldata data) external pure returns (string memory) {
    return LibString.prefixBase32(data);
  }

  function prefixHexadecimal(string calldata data) external pure returns (string memory) {
    return LibString.prefixHexadecimal(data);
  }

  function bytesToBase32(bytes calldata data) external pure returns (string memory) {
    return LibString.bytesToBase32(data);
  }

  function bytesToHexadecimal(bytes calldata data) external pure returns (string memory) {
    return LibString.bytesToHexadecimal(data);
  }
}


================================================
FILE: contracts/mocks/ModuleMock.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


contract ModuleMock {
  event Pong();

  function ping() external {
    emit Pong();
  }
}


================================================
FILE: contracts/modules/GuestModule.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "../utils/LibOptim.sol";

import "./commons/submodules/auth/SequenceBaseSig.sol";

import "./commons/ModuleAuth.sol";
import "./commons/ModuleCalls.sol";
import "./commons/ModuleCreator.sol";


/**
 * GuestModule implements a Sequence wallet without signatures, nonce or replay protection.
 * executing transactions using this wallet is not an authenticated process, and can be done by any address.
 *
 * @notice This contract is completely public with no security, designed to execute pre-signed transactions
 *   and use Sequence tools without using the wallets.
 */
contract GuestModule is
  ModuleAuth,
  ModuleCalls,
  ModuleCreator
{
  error DelegateCallNotAllowed(uint256 _index);
  error NotSupported();

  /**
   * @notice Allow any caller to execute an action
   * @param _txs Transactions to process
   */
  function execute(
    Transaction[] calldata _txs,
    uint256,
    bytes calldata
  ) public override {
    // Hash transaction bundle
    bytes32 txHash = SequenceBaseSig.subdigest(keccak256(abi.encode('guest:', _txs)));

    // Execute the transactions
    _executeGuest(txHash, _txs);
  }

  /**
   * @notice Allow any caller to execute an action
   * @param _txs Transactions to process
   */
  function selfExecute(
    Transaction[] calldata _txs
  ) public override {
    // Hash transaction bundle
    bytes32 txHash = SequenceBaseSig.subdigest(keccak256(abi.encode('self:', _txs)));

    // Execute the transactions
    _executeGuest(txHash, _txs);
  }

  /**
   * @notice Executes a list of transactions
   * @param _txHash  Hash of the batch of transactions
   * @param _txs  Transactions to execute
   */
  function _executeGuest(
    bytes32 _txHash,
    Transaction[] calldata _txs
  ) private {
    // Execute transaction
    uint256 size = _txs.length;
    for (uint256 i = 0; i < size; i++) {
      Transaction calldata transaction = _txs[i];

      if (transaction.delegateCall) revert DelegateCallNotAllowed(i);

      uint256 gasLimit = transaction.gasLimit;
      if (gasleft() < gasLimit) revert NotEnoughGas(i, gasLimit, gasleft());

      bool success = LibOptim.call(
        transaction.target,
        transaction.value,
        gasLimit == 0 ? gasleft() : gasLimit,
        transaction.data
      );

      if (success) {
        emit TxExecuted(_txHash, i);
      } else {
        _revertBytes(
          transaction.revertOnError,
          _txHash,
          i,
          LibOptim.returnData()
        );
      }
    }
  }

  /**
   * @notice Validates any signature image, because the wallet is public and has no owner.
   * @return true, all signatures are valid.
   */
  function _isValidImage(bytes32) internal override pure returns (bool) {
    return true;
  }

  /**
   * Not supported.
   */
  function _updateImageHash(bytes32) internal override virtual {
    revert NotSupported();
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(
    bytes4 _interfaceID
  ) public override (
    ModuleAuth,
    ModuleCalls,
    ModuleCreator
  ) pure returns (bool) {
    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/MainModule.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./commons/ModuleAuthFixed.sol";
import "./commons/ModuleHooks.sol";
import "./commons/ModuleCalls.sol";
import "./commons/ModuleCreator.sol";
import "./commons/ModuleExtraAuth.sol";
import "./commons/ModuleAuthConvenience.sol";


/**
 * @notice Contains the core functionality Sequence wallets will inherit.
 * @dev If using a new main module, developers must ensure that all inherited
 *      contracts by the main module don't conflict and are accounted for to be
 *      supported by the supportsInterface method.
 */
contract MainModule is
  ModuleAuthFixed,
  ModuleExtraAuth,
  ModuleCalls,
  ModuleHooks,
  ModuleCreator,
  ModuleAuthConvenience
{
  constructor(
    address _factory,
    address _mainModuleUpgradable
  ) ModuleAuthFixed(
    _factory,
    _mainModuleUpgradable
  ) { }

  function _isValidImage(
    bytes32 _imageHash
  ) internal override(
    IModuleAuth,
    ModuleAuthFixed,
    ModuleExtraAuth
  ) view returns (bool) {
    return super._isValidImage(_imageHash);
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(
    bytes4 _interfaceID
  ) public override(
    ModuleAuthFixed,
    ModuleAuthConvenience,
    ModuleCalls,
    ModuleExtraAuth,
    ModuleHooks,
    ModuleCreator
  ) pure returns (bool) {
    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/MainModuleGasEstimation.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./commons/gas-estimation/ModuleIgnoreAuthUpgradable.sol";
import "./commons/gas-estimation/ModuleIgnoreNonceCalls.sol";
import "./commons/ModuleHooks.sol";
import "./commons/ModuleUpdate.sol";
import "./commons/ModuleCreator.sol";


/**
 * @notice Contains an alternative implementation of the MainModules that skips validation of
 *   signatures, this implementation SHOULD NOT be used directly on a wallet.
 *
 *   Intended to be used only for gas estimation, using eth_call and overrides.
 */
contract MainModuleGasEstimation is
  ModuleIgnoreAuthUpgradable,
  ModuleIgnoreNonceCalls,
  ModuleUpdate,
  ModuleHooks,
  ModuleCreator
{
  struct SimulateResult {
    bool executed;
    bool succeeded;
    bytes result;
    uint256 gasUsed;
  }

  /**
   * @notice Simulate each transaction in a bundle for gas usage and execution result
   * @param _txs Transactions to process
   * @return The gas used and execution result for each transaction in the bundle
   */
  function simulateExecute(Transaction[] calldata _txs) public virtual returns (SimulateResult[] memory) {
    unchecked {
      SimulateResult[] memory results = new SimulateResult[](_txs.length);

      // Execute transaction
      uint256 size = _txs.length;
      for (uint256 i = 0; i < size; i++) {
        Transaction calldata transaction = _txs[i];
        uint256 gasLimit = transaction.gasLimit;

        results[i].executed = true;

        if (gasleft() < gasLimit) {
          results[i].succeeded = false;
          results[i].result = abi.encodeWithSelector(IModuleCalls.NotEnoughGas.selector, i, gasLimit, gasleft());
          break;
        }

        if (transaction.delegateCall) {
          uint256 initialGas = gasleft();

          (results[i].succeeded, results[i].result) = transaction.target.delegatecall{
            gas: gasLimit == 0 ? gasleft() : gasLimit
          }(transaction.data);

          results[i].gasUsed = initialGas - gasleft();
        } else {
          uint256 initialGas = gasleft();

          (results[i].succeeded, results[i].result) = transaction.target.call{
            value: transaction.value,
            gas: gasLimit == 0 ? gasleft() : gasLimit
          }(transaction.data);

          results[i].gasUsed = initialGas - gasleft();
        }

        if (!results[i].succeeded && transaction.revertOnError) {
          break;
        }
      }

      return results;
    }
  }

  function _isValidImage(bytes32 _imageHash) internal override(
    IModuleAuth,
    ModuleIgnoreAuthUpgradable
  ) view returns (bool) {
    return super._isValidImage(_imageHash);
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @dev If using a new main module, developers must ensure that all inherited
   *      contracts by the main module don't conflict and are accounted for to be
   *      supported by the supportsInterface method.
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(
    bytes4 _interfaceID
  ) public override(
    ModuleAuthUpgradable,
    ModuleCalls,
    ModuleUpdate,
    ModuleHooks,
    ModuleCreator
  ) pure returns (bool) {
    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/MainModuleUpgradable.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./commons/ModuleAuthUpgradable.sol";
import "./commons/ModuleHooks.sol";
import "./commons/ModuleCalls.sol";
import "./commons/ModuleUpdate.sol";
import "./commons/ModuleCreator.sol";
import "./commons/ModuleExtraAuth.sol";
import "./commons/ModuleAuthConvenience.sol";


/**
 * @notice Contains the core functionality Sequence wallets will inherit with
 *         the added functionality that the main module can be changed.
 * @dev If using a new main module, developers must ensure that all inherited
 *      contracts by the main module don't conflict and are accounted for to be
 *      supported by the supportsInterface method.
 */
contract MainModuleUpgradable is
  ModuleAuthUpgradable,
  ModuleExtraAuth,
  ModuleCalls,
  ModuleUpdate,
  ModuleHooks,
  ModuleCreator,
  ModuleAuthConvenience
{
  function _isValidImage(
    bytes32 _imageHash
  ) internal override(
    IModuleAuth,
    ModuleAuthUpgradable,
    ModuleExtraAuth
  ) view returns (bool) {
    return super._isValidImage(_imageHash);
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @dev If using a new main module, developers must ensure that all inherited
   *      contracts by the main module don't conflict and are accounted for to be
   *      supported by the supportsInterface method.
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(
    bytes4 _interfaceID
  ) public override(
    ModuleAuthUpgradable,
    ModuleAuthConvenience,
    ModuleCalls,
    ModuleExtraAuth,
    ModuleUpdate,
    ModuleHooks,
    ModuleCreator
  ) pure returns (bool) {
    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/commons/Implementation.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

/**
 * @dev Allows modules to access the implementation slot
 */
contract Implementation {
  /**
   * @notice Updates the Wallet implementation
   * @param _imp New implementation address
   * @dev The wallet implementation is stored on the storage slot
   *   defined by the address of the wallet itself
   *   WARNING updating this value may break the wallet and users
   *   must be confident that the new implementation is safe.
   */
  function _setImplementation(address _imp) internal {
    assembly {
      sstore(address(), _imp)
    }
  }

  /**
   * @notice Returns the Wallet implementation
   * @return _imp The address of the current Wallet implementation
   */
  function _getImplementation() internal view returns (address _imp) {
    assembly {
      _imp := sload(address())
    }
  }
}


================================================
FILE: contracts/modules/commons/ModuleAuth.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "../../utils/LibBytes.sol";
import "../../interfaces/IERC1271Wallet.sol";

import "./interfaces/IModuleAuth.sol";

import "./ModuleERC165.sol";

import "./submodules/auth/SequenceBaseSig.sol";
import "./submodules/auth/SequenceDynamicSig.sol";
import "./submodules/auth/SequenceNoChainIdSig.sol";
import "./submodules/auth/SequenceChainedSig.sol";


abstract contract ModuleAuth is
  IModuleAuth,
  ModuleERC165,
  IERC1271Wallet,
  SequenceChainedSig
{
  using LibBytes for bytes;

  bytes1 internal constant LEGACY_TYPE = hex"00";
  bytes1 internal constant DYNAMIC_TYPE = hex"01";
  bytes1 internal constant NO_CHAIN_ID_TYPE = hex"02";
  bytes1 internal constant CHAINED_TYPE = hex"03";

  bytes4 internal constant SELECTOR_ERC1271_BYTES_BYTES = 0x20c13b0b;
  bytes4 internal constant SELECTOR_ERC1271_BYTES32_BYTES = 0x1626ba7e;

  /**
   * @notice Recovers the threshold, weight, imageHash, subdigest, and checkpoint of a signature.
   * @dev The signature must be prefixed with a type byte, which is used to determine the recovery method.
   *
   * @param _digest Digest of the signed data.
   * @param _signature A Sequence signature.
   *
   * @return threshold The required number of signatures needed to consider the signature valid.
   * @return weight The actual number of signatures collected in the signature.
   * @return imageHash The imageHash of the configuration that signed the message.
   * @return subdigest A modified version of the original digest, unique for each wallet/network.
   * @return checkpoint A nonce that is incremented every time a new configuration is set.
   */
  function signatureRecovery(
    bytes32 _digest,
    bytes calldata _signature
  ) public override virtual view returns (
    uint256 threshold,
    uint256 weight,
    bytes32 imageHash,
    bytes32 subdigest,
    uint256 checkpoint
  ) {
    bytes1 signatureType = _signature[0];

    if (signatureType == LEGACY_TYPE) {
      // networkId digest + base recover
      subdigest = SequenceBaseSig.subdigest(_digest);
      (threshold, weight, imageHash, checkpoint) = SequenceBaseSig.recover(subdigest, _signature);
      return (threshold, weight, imageHash, subdigest, checkpoint);
    }

    if (signatureType == DYNAMIC_TYPE) {
      // networkId digest + dynamic recover
      subdigest = SequenceBaseSig.subdigest(_digest);
      (threshold, weight, imageHash, checkpoint) = SequenceDynamicSig.recover(subdigest, _signature);
      return (threshold, weight, imageHash, subdigest, checkpoint);
    }

    if (signatureType == NO_CHAIN_ID_TYPE) {
      // noChainId digest + dynamic recover
      subdigest = SequenceNoChainIdSig.subdigest(_digest);
      (threshold, weight, imageHash, checkpoint) = SequenceDynamicSig.recover(subdigest, _signature);
      return (threshold, weight, imageHash, subdigest, checkpoint);
    }

    if (signatureType == CHAINED_TYPE) {
      // original digest + chained recover
      // (subdigest will be computed in the chained recover)
      return chainedRecover(_digest, _signature);
    }

    revert InvalidSignatureType(signatureType);
  }

  /**
   * @dev Validates a signature.
   *
   * @param _digest Digest of the signed data.
   * @param _signature A Sequence signature.
   *
   * @return isValid Indicates whether the signature is valid or not.
   * @return subdigest A modified version of the original digest, unique for each wallet/network.
   */
  function _signatureValidation(
    bytes32 _digest,
    bytes calldata _signature
  ) internal override virtual view returns (
    bool isValid,
    bytes32 subdigest
  ) {
    uint256 threshold; uint256 weight; bytes32 imageHash;
    (threshold, weight, imageHash, subdigest,) = signatureRecovery(_digest, _signature);
    isValid = weight >= threshold && _isValidImage(imageHash);
  }

  /**
   * @notice Verifies whether the provided signature is valid with respect to the provided data
   * @dev MUST return the correct magic value if the signature provided is valid for the provided data
   *   > The bytes4 magic value to return when signature is valid is 0x20c13b0b : bytes4(keccak256("isValidSignature(bytes,bytes)"))
   * @param _data       Arbitrary length data signed on the behalf of address(this)
   * @param _signatures Signature byte array associated with _data.
   *                    Encoded as abi.encode(Signature[], Configs)
   * @return magicValue Magic value 0x20c13b0b if the signature is valid and 0x0 otherwise
   */
  function isValidSignature(
    bytes calldata _data,
    bytes calldata _signatures
  ) public override virtual view returns (bytes4) {
    // Validate signatures
    (bool isValid,) = _signatureValidation(keccak256(_data), _signatures);
    if (isValid) {
      return SELECTOR_ERC1271_BYTES_BYTES;
    }

    return bytes4(0);
  }

  /**
   * @notice Verifies whether the provided signature is valid with respect to the provided hash
   * @dev MUST return the correct magic value if the signature provided is valid for the provided hash
   *   > The bytes4 magic value to return when signature is valid is 0x1626ba7e : bytes4(keccak256("isValidSignature(bytes32,bytes)"))
   * @param _hash       keccak256 hash that was signed
   * @param _signatures Signature byte array associated with _data.
   *                    Encoded as abi.encode(Signature[], Configs)
   * @return magicValue Magic value 0x1626ba7e if the signature is valid and 0x0 otherwise
   */
  function isValidSignature(
    bytes32 _hash,
    bytes calldata _signatures
  ) public override virtual view returns (bytes4) {
    // Validate signatures
    (bool isValid,) = _signatureValidation(_hash, _signatures);
    if (isValid) {
      return SELECTOR_ERC1271_BYTES32_BYTES;
    }

    return bytes4(0);
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(bytes4 _interfaceID) public override virtual pure returns (bool) {
    if (
      _interfaceID == type(IModuleAuth).interfaceId ||
      _interfaceID == type(IERC1271Wallet).interfaceId
    ) {
      return true;
    }

    return super.supportsInterface(_interfaceID);
  }

  /**
   * @notice Updates the signers configuration of the wallet
   * @param _imageHash New required image hash of the signature
   */
  function updateImageHash(bytes32 _imageHash) external override virtual onlySelf {
    _updateImageHash(_imageHash);
  }
}


================================================
FILE: contracts/modules/commons/ModuleAuthConvenience.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./ModuleSelfAuth.sol";
import "./ModuleAuth.sol";
import "./ModuleIPFS.sol";
import "./ModuleERC165.sol";

import "../../utils/LibString.sol";



abstract contract ModuleAuthConvenience is ModuleERC165, ModuleSelfAuth, ModuleAuth, ModuleIPFS {

  /**
  * @notice Updates the image hash and the IPFS root in a single operation.
  * @dev These two operations are often performed together, so this function
  *      allows to save some gas by performing them in a single step.
  *
  * @param _imageHash The new image hash to be set.
  * @param _ipfsRoot The new IPFS root to be set.
  */
  function updateImageHashAndIPFS(
    bytes32 _imageHash,
    bytes32 _ipfsRoot
  ) external onlySelf {
    _updateImageHash(_imageHash);
    _updateIPFSRoot(_ipfsRoot);
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(bytes4 _interfaceID) public override (
    ModuleERC165,
    ModuleAuth
  ) virtual pure returns (bool) {
    if (_interfaceID == type(ModuleAuthConvenience).interfaceId) {
      return true;
    }

    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/commons/ModuleAuthFixed.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./ModuleAuth.sol";
import "./ModuleUpdate.sol";
import "./ModuleSelfAuth.sol";
import "./ModuleStorage.sol";

import "../../Wallet.sol";

/**
 *  Implements ModuleAuth by validating the signature image against
 *  the salt used to deploy the contract
 *
 *  This module allows wallets to be deployed with a default configuration
 *  without using any aditional contract storage
 */
abstract contract ModuleAuthFixed is ModuleSelfAuth, ModuleAuth, ModuleUpdate {
  bytes32 public immutable INIT_CODE_HASH;
  address public immutable FACTORY;
  address public immutable UPGRADEABLE_IMPLEMENTATION;

  constructor(address _factory, address _mainModuleUpgradeable) {
    // Build init code hash of the deployed wallets using that module
    bytes32 initCodeHash = keccak256(abi.encodePacked(Wallet.creationCode, uint256(uint160(address(this)))));

    INIT_CODE_HASH = initCodeHash;
    FACTORY = _factory;
    UPGRADEABLE_IMPLEMENTATION = _mainModuleUpgradeable;
  }

  /**
   * @notice Updates the configuration of the wallet
   * @dev In the process of updating the configuration, the wallet implementation
   *      is updated to the mainModuleUpgradeable, this only happens once in the
   *      lifetime of the wallet.
   *
   * @param _imageHash New required image hash of the signature
   */
  function _updateImageHash(bytes32 _imageHash) internal override virtual {
    // Update imageHash in storage
    if (_imageHash == bytes32(0)) revert ImageHashIsZero();
    ModuleStorage.writeBytes32(IMAGE_HASH_KEY, _imageHash);
    emit ImageHashUpdated(_imageHash);

    // Update wallet implementation to mainModuleUpgradeable
    _updateImplementation(UPGRADEABLE_IMPLEMENTATION);
  }

  /**
   * @notice Validates the signature image with the salt used to deploy the contract
   * @param _imageHash Hash image of signature
   * @return true if the signature image is valid
   */
  function _isValidImage(bytes32 _imageHash) internal override virtual view returns (bool) {
    return address(
      uint160(
        uint256(
          keccak256(
            abi.encodePacked(
              hex"ff",
              FACTORY,
              _imageHash,
              INIT_CODE_HASH
            )
          )
        )
      )
    ) == address(this);
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(bytes4 _interfaceID) public override(ModuleAuth, ModuleUpdate) virtual pure returns (bool) {
    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/commons/ModuleAuthUpgradable.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./interfaces/IModuleAuthUpgradable.sol";

import "./ModuleSelfAuth.sol";
import "./ModuleAuth.sol";
import "./ModuleStorage.sol";


abstract contract ModuleAuthUpgradable is IModuleAuthUpgradable, ModuleSelfAuth, ModuleAuth {
  /**
   * @notice Updates the signers configuration of the wallet
   * @param _imageHash New required image hash of the signature
   */
  function _updateImageHash(bytes32 _imageHash) internal override virtual {
    if (_imageHash == bytes32(0)) revert ImageHashIsZero();
    ModuleStorage.writeBytes32(IMAGE_HASH_KEY, _imageHash);
    emit ImageHashUpdated(_imageHash);
  }

  /**
   * @notice Returns the current image hash of the wallet
   */
  function imageHash() external override virtual view returns (bytes32) {
    return ModuleStorage.readBytes32(IMAGE_HASH_KEY);
  }

  /**
   * @notice Validates the signature image with a valid image hash defined
   *   in the contract storage
   * @param _imageHash Hash image of signature
   * @return true if the signature image is valid
   */
  function _isValidImage(bytes32 _imageHash) internal override virtual view returns (bool) {
    return _imageHash != bytes32(0) && _imageHash == ModuleStorage.readBytes32(IMAGE_HASH_KEY);
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(bytes4 _interfaceID) public override virtual pure returns (bool) {
    if (_interfaceID == type(IModuleAuthUpgradable).interfaceId) {
      return true;
    }

    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/commons/ModuleCalls.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./ModuleSelfAuth.sol";
import "./ModuleStorage.sol";
import "./ModuleERC165.sol";
import "./ModuleNonce.sol";
import "./ModuleOnlyDelegatecall.sol";

import "./interfaces/IModuleCalls.sol";
import "./interfaces/IModuleAuth.sol";

import "./submodules/nonce/SubModuleNonce.sol";
import "./submodules/auth/SequenceBaseSig.sol";

import "../../utils/LibOptim.sol";


abstract contract ModuleCalls is IModuleCalls, IModuleAuth, ModuleERC165, ModuleOnlyDelegatecall, ModuleSelfAuth, ModuleNonce {
  /**
   * @notice Allow wallet owner to execute an action
   * @dev Relayers must ensure that the gasLimit specified for each transaction
   *      is acceptable to them. A user could specify large enough that it could
   *      consume all the gas available.
   * @param _txs        Transactions to process
   * @param _nonce      Signature nonce (may contain an encoded space)
   * @param _signature  Encoded signature
   */
  function execute(
    Transaction[] calldata _txs,
    uint256 _nonce,
    bytes calldata _signature
  ) external override virtual onlyDelegatecall {
    // Validate and update nonce
    _validateNonce(_nonce);

    // Hash and verify transaction bundle
    (bool isValid, bytes32 txHash) = _signatureValidation(
      keccak256(
        abi.encode(
          _nonce,
          _txs
        )
      ),
      _signature
    );

    if (!isValid) {
      revert InvalidSignature(txHash, _signature);
    }

    // Execute the transactions
    _execute(txHash, _txs);
  }

  /**
   * @notice Allow wallet to execute an action
   *   without signing the message
   * @param _txs  Transactions to execute
   */
  function selfExecute(
    Transaction[] calldata _txs
  ) external override virtual onlySelf {
    // Hash transaction bundle
    bytes32 txHash = SequenceBaseSig.subdigest(
      keccak256(
        abi.encode('self:', _txs)
      )
    );

    // Execute the transactions
    _execute(txHash, _txs);
  }

  /**
   * @notice Executes a list of transactions
   * @param _txHash  Hash of the batch of transactions
   * @param _txs  Transactions to execute
   */
  function _execute(
    bytes32 _txHash,
    Transaction[] calldata _txs
  ) private {
    unchecked {
      // Execute transaction
      uint256 size = _txs.length;
      for (uint256 i = 0; i < size; i++) {
        Transaction calldata transaction = _txs[i];
        uint256 gasLimit = transaction.gasLimit;

        if (gasleft() < gasLimit) revert NotEnoughGas(i, gasLimit, gasleft());

        bool success;
        if (transaction.delegateCall) {
          success = LibOptim.delegatecall(
            transaction.target,
            gasLimit == 0 ? gasleft() : gasLimit,
            transaction.data
          );
        } else {
          success = LibOptim.call(
            transaction.target,
            transaction.value,
            gasLimit == 0 ? gasleft() : gasLimit,
            transaction.data
          );
        }

        if (success) {
          emit TxExecuted(_txHash, i);
        } else {
          // Avoid copy of return data until neccesary
          _revertBytes(
            transaction.revertOnError,
            _txHash,
            i,
            LibOptim.returnData()
          );
        }
      }
    }
  }

  /**
   * @notice Logs a failed transaction, reverts if the transaction is not optional
   * @param _revertOnError  Signals if it should revert or just log
   * @param _txHash         Hash of the transaction
   * @param _index          Index of the transaction in the batch
   * @param _reason         Encoded revert message
   */
  function _revertBytes(
    bool _revertOnError,
    bytes32 _txHash,
    uint256 _index,
    bytes memory _reason
  ) internal {
    if (_revertOnError) {
      assembly { revert(add(_reason, 0x20), mload(_reason)) }
    } else {
      emit TxFailed(_txHash, _index, _reason);
    }
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(bytes4 _interfaceID) public override virtual pure returns (bool) {
    if (_interfaceID == type(IModuleCalls).interfaceId) {
      return true;
    }

    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/commons/ModuleCreator.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./interfaces/IModuleCreator.sol";

import "./ModuleSelfAuth.sol";
import "./ModuleERC165.sol";


contract ModuleCreator is IModuleCreator, ModuleERC165, ModuleSelfAuth {
  event CreatedContract(address _contract);

  /**
   * @notice Creates a contract forwarding eth value
   * @param _code Creation code of the contract
   * @return addr The address of the created contract
   */
  function createContract(bytes memory _code) public override virtual payable onlySelf returns (address addr) {
    assembly { addr := create(callvalue(), add(_code, 32), mload(_code)) }
    if (addr == address(0)) revert CreateFailed(_code);
    emit CreatedContract(addr);
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(bytes4 _interfaceID) public override virtual pure returns (bool) {
    if (_interfaceID == type(IModuleCreator).interfaceId) {
      return true;
    }

    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/commons/ModuleERC165.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


abstract contract ModuleERC165 {
  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @dev Adding new hooks will not lead to them being reported by this function
   *      without upgrading the wallet. In addition, developers must ensure that
   *      all inherited contracts by the main module don't conflict and are accounted
   *      to be supported by the supportsInterface method.
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(bytes4 _interfaceID) virtual public pure returns (bool) {
    return _interfaceID == this.supportsInterface.selector;
  }
}


================================================
FILE: contracts/modules/commons/ModuleERC5719.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./ModuleIPFS.sol";

import "../../utils/LibString.sol";


contract ModuleERC5719 is ModuleIPFS {
  function getAlternativeSignature(bytes32 _digest) external view returns (string memory) {
    return string(
      abi.encodePacked(
        ipfsRoot(),
        "/ERC5719/",
        LibString.prefixHexadecimal(
          LibString.bytesToHexadecimal(
            abi.encodePacked(_digest)
          )
        )
      )
    );
  }
}


================================================
FILE: contracts/modules/commons/ModuleExtraAuth.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./ModuleAuth.sol";
import "./ModuleStorage.sol";
import "./ModuleSelfAuth.sol";
import "./ModuleERC165.sol";


abstract contract ModuleExtraAuth is ModuleERC165, ModuleSelfAuth, ModuleAuth {
  //                       EXTRA_IMAGE_HASH_KEY = keccak256("org.sequence.module.static.auth.extra.image.hash");
  bytes32 private constant EXTRA_IMAGE_HASH_KEY = bytes32(0x849e7bdc245db17e50b9f43086f1914d70eb4dab6dd89af4d541d53353ad97de);

  event SetExtraImageHash(bytes32 indexed _imageHash, uint256 _expiration);

  function _writeExpirationForImageHash(bytes32 _imageHash, uint256 _expiration) internal {
    ModuleStorage.writeBytes32Map(EXTRA_IMAGE_HASH_KEY, _imageHash, bytes32(_expiration));
  }

  function _readExpirationForImageHash(bytes32 _imageHash) internal view returns (uint256 _expiration) {
    return uint256(ModuleStorage.readBytes32Map(EXTRA_IMAGE_HASH_KEY, _imageHash));
  }

  function _isValidImage(bytes32 _imageHash) internal override virtual view returns (bool) {
    if (super._isValidImage(_imageHash)) {
      return true;
    }

    uint256 expiration = _readExpirationForImageHash(_imageHash);

    // solhint-disable-next-line not-rely-on-time
    return expiration != 0 && expiration > block.timestamp;
  }

  function extraImageHash(bytes32 _imageHash) public view returns (uint256) {
    return _readExpirationForImageHash(_imageHash);
  }

  function setExtraImageHash(bytes32 _imageHash, uint256 _expiration) external onlySelf {
    _writeExpirationForImageHash(_imageHash, _expiration);

    emit SetExtraImageHash(_imageHash, _expiration);
  }

  function clearExtraImageHashes(bytes32[] calldata _imageHashes) external onlySelf {
    unchecked {
      uint256 imageHashesLength = _imageHashes.length;
      for (uint256 i = 0; i < imageHashesLength; i++) {
        bytes32 imageHash = _imageHashes[i];
        _writeExpirationForImageHash(imageHash, 0);

       emit SetExtraImageHash(imageHash, 0);
      }
    }
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(bytes4 _interfaceID) public override (
    ModuleERC165,
    ModuleAuth
  ) virtual pure returns (bool) {
    if (_interfaceID == type(ModuleExtraAuth).interfaceId) {
      return true;
    }

    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/commons/ModuleHooks.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./interfaces/IModuleHooks.sol";

import "./ModuleSelfAuth.sol";
import "./ModuleStorage.sol";
import "./ModuleERC165.sol";

import "../../interfaces/receivers/IERC1155Receiver.sol";
import "../../interfaces/receivers/IERC721Receiver.sol";
import "../../interfaces/receivers/IERC223Receiver.sol";


contract ModuleHooks is IERC1155Receiver, IERC721Receiver, IModuleHooks, ModuleERC165, ModuleSelfAuth {
  //                       HOOKS_KEY = keccak256("org.arcadeum.module.hooks.hooks");
  bytes32 private constant HOOKS_KEY = bytes32(0xbe27a319efc8734e89e26ba4bc95f5c788584163b959f03fa04e2d7ab4b9a120);

  /**
   * @notice Reads the implementation hook of a signature
   * @param _signature Signature function
   * @return The address of the implementation hook, address(0) if none
  */
  function readHook(bytes4 _signature) external override virtual view returns (address) {
    return _readHook(_signature);
  }

  /**
   * @notice Adds a new hook to handle a given function selector
   * @param _signature Signature function linked to the hook
   * @param _implementation Hook implementation contract
   * @dev Can't overwrite hooks that are part of the main module (those defined below)
   */
  function addHook(bytes4 _signature, address _implementation) external override virtual onlySelf {
    if (_readHook(_signature) != address(0)) revert HookAlreadyExists(_signature);
    _writeHook(_signature, _implementation);
  }

  /**
   * @notice Removes a registered hook
   * @param _signature Signature function linked to the hook
   * @dev Can't remove hooks that are part of the main module (those defined below)
   *      without upgrading the wallet
   */
  function removeHook(bytes4 _signature) external override virtual onlySelf {
    if (_readHook(_signature) == address(0)) revert HookDoesNotExist(_signature);
    _writeHook(_signature, address(0));
  }

  /**
   * @notice Reads the implementation hook of a signature
   * @param _signature Signature function
   * @return The address of the implementation hook, address(0) if none
  */
  function _readHook(bytes4 _signature) private view returns (address) {
    return address(uint160(uint256(ModuleStorage.readBytes32Map(HOOKS_KEY, _signature))));
  }

  /**
   * @notice Writes the implementation hook of a signature
   * @param _signature Signature function
   * @param _implementation Hook implementation contract
  */
  function _writeHook(bytes4 _signature, address _implementation) private {
    ModuleStorage.writeBytes32Map(HOOKS_KEY, _signature, bytes32(uint256(uint160(_implementation))));
    emit DefinedHook(_signature, _implementation);
  }

  /**
   * @notice Handle the receipt of a single ERC1155 token type.
   * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
   */
  function onERC1155Received(
    address,
    address,
    uint256,
    uint256,
    bytes calldata
  ) external override virtual returns (bytes4) {
    return ModuleHooks.onERC1155Received.selector;
  }

  /**
   * @notice Handle the receipt of multiple ERC1155 token types.
   * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
   */
  function onERC1155BatchReceived(
    address,
    address,
    uint256[] calldata,
    uint256[] calldata,
    bytes calldata
  ) external override virtual returns (bytes4) {
    return ModuleHooks.onERC1155BatchReceived.selector;
  }

  /**
   * @notice Handle the receipt of a single ERC721 token.
   * @return `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
   */
  function onERC721Received(address, address, uint256, bytes calldata) external override virtual returns (bytes4) {
    return ModuleHooks.onERC721Received.selector;
  }

  /**
   * @notice Routes fallback calls through hooks
   */
  fallback() external payable {
    if (msg.data.length >= 4) {
      address target = _readHook(msg.sig);
      if (target != address(0)) {
        (bool success, bytes memory result) = target.delegatecall(msg.data);
        assembly {
          if iszero(success)  {
            revert(add(result, 0x20), mload(result))
          }

          return(add(result, 0x20), mload(result))
        }
      }
    }
  }

  /**
   * @notice Allows the wallet to receive ETH
   */
  receive() external payable { }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(bytes4 _interfaceID) public override virtual pure returns (bool) {
    if (
      _interfaceID == type(IModuleHooks).interfaceId ||
      _interfaceID == type(IERC1155Receiver).interfaceId ||
      _interfaceID == type(IERC721Receiver).interfaceId ||
      _interfaceID == type(IERC223Receiver).interfaceId
    ) {
      return true;
    }

    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/commons/ModuleIPFS.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./ModuleSelfAuth.sol";
import "./ModuleStorage.sol";

import "../../utils/LibString.sol";


contract ModuleIPFS is ModuleSelfAuth {
  event IPFSRootUpdated(bytes32 _hash);

  //                       IPFS_ROOT_KEY = keccak256("sequence.ipfs.root")
  bytes32 private constant IPFS_ROOT_KEY = bytes32(0x0eecac93ced8722d209199364cda3bc33da3bc3a23daef6be49ebd780511d033);

  function ipfsRootBytes32() public view returns (bytes32) {
    return ModuleStorage.readBytes32(IPFS_ROOT_KEY);
  }

  function ipfsRoot() public view returns (string memory) {
    return string(
      abi.encodePacked(
        "ipfs://",
        LibString.prefixBase32(
          LibString.bytesToBase32(
            abi.encodePacked(
              hex'01701220',
              ipfsRootBytes32()
            )
          )
        )
      )
    );
  }

  function updateIPFSRoot(bytes32 _hash) external onlySelf {
    _updateIPFSRoot(_hash);
  }

  function _updateIPFSRoot(bytes32 _hash) internal {
    ModuleStorage.writeBytes32(IPFS_ROOT_KEY, _hash);
    emit IPFSRootUpdated(_hash);
  }
}


================================================
FILE: contracts/modules/commons/ModuleNonce.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./ModuleStorage.sol";

import "./submodules/nonce/SubModuleNonce.sol";


contract ModuleNonce {
  // Events
  event NonceChange(uint256 _space, uint256 _newNonce);

  // Errors
  error BadNonce(uint256 _space, uint256 _provided, uint256 _current);

  //                       NONCE_KEY = keccak256("org.arcadeum.module.calls.nonce");
  bytes32 private constant NONCE_KEY = bytes32(0x8d0bf1fd623d628c741362c1289948e57b3e2905218c676d3e69abee36d6ae2e);

  /**
   * @notice Returns the next nonce of the default nonce space
   * @dev The default nonce space is 0x00
   * @return The next nonce
   */
  function nonce() external virtual view returns (uint256) {
    return readNonce(0);
  }

  /**
   * @notice Returns the next nonce of the given nonce space
   * @param _space Nonce space, each space keeps an independent nonce count
   * @return The next nonce
   */
  function readNonce(uint256 _space) public virtual view returns (uint256) {
    return uint256(ModuleStorage.readBytes32Map(NONCE_KEY, bytes32(_space)));
  }

  /**
   * @notice Changes the next nonce of the given nonce space
   * @param _space Nonce space, each space keeps an independent nonce count
   * @param _nonce Nonce to write on the space
   */
  function _writeNonce(uint256 _space, uint256 _nonce) internal {
    ModuleStorage.writeBytes32Map(NONCE_KEY, bytes32(_space), bytes32(_nonce));
  }

  /**
   * @notice Verify if a nonce is valid
   * @param _rawNonce Nonce to validate (may contain an encoded space)
   */
  function _validateNonce(uint256 _rawNonce) internal virtual {
    // Retrieve current nonce for this wallet
    (uint256 space, uint256 providedNonce) = SubModuleNonce.decodeNonce(_rawNonce);

    uint256 currentNonce = readNonce(space);
    if (currentNonce != providedNonce) {
      revert BadNonce(space, providedNonce, currentNonce);
    }

    unchecked {
      uint256 newNonce = providedNonce + 1;

      _writeNonce(space, newNonce);
      emit NonceChange(space, newNonce);
      return;
    }
  }
}


================================================
FILE: contracts/modules/commons/ModuleOnlyDelegatecall.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


contract ModuleOnlyDelegatecall {
  address private immutable self;

  error OnlyDelegatecall();

  constructor() {
    self = address(this);
  }

  /**
   * @notice Modifier that only allows functions to be called via delegatecall.
   */
  modifier onlyDelegatecall() {
    if (address(this) == self) {
      revert OnlyDelegatecall();
    }
    _;
  }
}


================================================
FILE: contracts/modules/commons/ModuleSelfAuth.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


contract ModuleSelfAuth {
  error OnlySelfAuth(address _sender, address _self);

  modifier onlySelf() {
    if (msg.sender != address(this)) {
      revert OnlySelfAuth(msg.sender, address(this));
    }
    _;
  }
}


================================================
FILE: contracts/modules/commons/ModuleStorage.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


library ModuleStorage {
  function writeBytes32(bytes32 _key, bytes32 _val) internal {
    assembly { sstore(_key, _val) }
  }

  function readBytes32(bytes32 _key) internal view returns (bytes32 val) {
    assembly { val := sload(_key) }
  }

  function writeBytes32Map(bytes32 _key, bytes32 _subKey, bytes32 _val) internal {
    bytes32 key = keccak256(abi.encode(_key, _subKey));
    assembly { sstore(key, _val) }
  }

  function readBytes32Map(bytes32 _key, bytes32 _subKey) internal view returns (bytes32 val) {
    bytes32 key = keccak256(abi.encode(_key, _subKey));
    assembly { val := sload(key) }
  }
}


================================================
FILE: contracts/modules/commons/ModuleUpdate.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./interfaces/IModuleUpdate.sol";

import "./Implementation.sol";
import "./ModuleSelfAuth.sol";
import "./ModuleERC165.sol";

import "../../utils/LibAddress.sol";


contract ModuleUpdate is IModuleUpdate, ModuleERC165, ModuleSelfAuth, Implementation {
  using LibAddress for address;

  event ImplementationUpdated(address newImplementation);

  /**
   * @notice Updates the implementation of the base wallet
   * @param _implementation New main module implementation
   * @dev WARNING Updating the implementation can brick the wallet
   */
  function updateImplementation(address _implementation) external override virtual onlySelf {
    _updateImplementation(_implementation);
  }

  /**
   * @notice Updates the implementation of the base wallet, used internally.
   * @param _implementation New main module implementation
   * @dev WARNING Updating the implementation can brick the wallet
   */
  function _updateImplementation(address _implementation) internal override virtual {
    if (!_implementation.isContract()) revert InvalidImplementation(_implementation);
    _setImplementation(_implementation);
    emit ImplementationUpdated(_implementation);
  }

  /**
   * @notice Query if a contract implements an interface
   * @param _interfaceID The interface identifier, as specified in ERC-165
   * @return `true` if the contract implements `_interfaceID`
   */
  function supportsInterface(bytes4 _interfaceID) public override virtual pure returns (bool) {
    if (_interfaceID == type(IModuleUpdate).interfaceId) {
      return true;
    }

    return super.supportsInterface(_interfaceID);
  }
}


================================================
FILE: contracts/modules/commons/gas-estimation/ModuleIgnoreAuthUpgradable.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./../ModuleAuthUpgradable.sol";


/**
  @notice Implements ModuleAuthUpgradable but ignores the validity of the signature
    should only be used during gas estimation.
*/
abstract contract ModuleIgnoreAuthUpgradable is ModuleAuthUpgradable {
  /**
   * @notice Removes the signature validation from the module, by returning true for any _imageHash
   * @param _imageHash Hash image of signature
   * @return true always
   */
  function _isValidImage(bytes32 _imageHash) internal override(ModuleAuthUpgradable) virtual view returns (bool) {
    // Still validates the imageHash using the original mechanism for a more acurate estimation
    return super._isValidImage(_imageHash) || true;
  }
}


================================================
FILE: contracts/modules/commons/gas-estimation/ModuleIgnoreNonceCalls.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./../ModuleCalls.sol";

import "./../submodules/nonce/SubModuleNonce.sol";


/**
  @notice Implements ModuleCalls but ignores the validity of the nonce
    should only be used during gas estimation.
*/
abstract contract ModuleIgnoreNonceCalls is ModuleCalls {

  /**
   * @notice Verify if a nonce is valid
   * @param _rawNonce Nonce to validate (may contain an encoded space)
   */
  function _validateNonce(uint256 _rawNonce) internal override virtual {
    // Retrieve current nonce for this wallet
    (uint256 space, uint256 providedNonce) = SubModuleNonce.decodeNonce(_rawNonce);

    uint256 currentNonce = readNonce(space);
    if (currentNonce != providedNonce && false) {
      revert BadNonce(space, providedNonce, currentNonce);
    }

    unchecked {
      uint256 newNonce = providedNonce + 1;

      _writeNonce(space, newNonce);
      emit NonceChange(space, newNonce);
      return;
    }
  }
}


================================================
FILE: contracts/modules/commons/interfaces/IModuleAuth.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


abstract contract IModuleAuth {
  //                        IMAGE_HASH_KEY = keccak256("org.arcadeum.module.auth.upgradable.image.hash");
  bytes32 internal constant IMAGE_HASH_KEY = bytes32(0xea7157fa25e3aa17d0ae2d5280fa4e24d421c61842aa85e45194e1145aa72bf8);

  event ImageHashUpdated(bytes32 newImageHash);

  // Errors
  error ImageHashIsZero();
  error InvalidSignatureType(bytes1 _type);

  function _signatureValidation(
    bytes32 _digest,
    bytes calldata _signature
  ) internal virtual view returns (
    bool isValid,
    bytes32 subdigest
  );

  function signatureRecovery(
    bytes32 _digest,
    bytes calldata _signature
  ) public virtual view returns (
    uint256 threshold,
    uint256 weight,
    bytes32 imageHash,
    bytes32 subdigest,
    uint256 checkpoint
  );

  /**
   * @notice Validates the signature image
   * @return true if the signature image is valid
   */
  function _isValidImage(bytes32) internal virtual view returns (bool) {
    return false;
  }

  /**
   * @notice Updates the signers configuration of the wallet
   * @param _imageHash New required image hash of the signature
   */
  function updateImageHash(bytes32 _imageHash) external virtual;

  /**
   * @notice Updates the signers configuration of the wallet
   * @param _imageHash New required image hash of the signature
   */
  function _updateImageHash(bytes32 _imageHash) internal virtual;
}


================================================
FILE: contracts/modules/commons/interfaces/IModuleAuthUpgradable.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


interface IModuleAuthUpgradable {
  /**
   * @notice Returns the current image hash of the wallet
   */
  function imageHash() external view returns (bytes32);
}


================================================
FILE: contracts/modules/commons/interfaces/IModuleCalls.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


interface IModuleCalls {
  // Events
  event TxFailed(bytes32 indexed _tx, uint256 _index, bytes _reason);
  event TxExecuted(bytes32 indexed _tx, uint256 _index);

  // Errors
  error NotEnoughGas(uint256 _index, uint256 _requested, uint256 _available);
  error InvalidSignature(bytes32 _hash, bytes _signature);

  // Transaction structure
  struct Transaction {
    bool delegateCall;   // Performs delegatecall
    bool revertOnError;  // Reverts transaction bundle if tx fails
    uint256 gasLimit;    // Maximum gas to be forwarded
    address target;      // Address of the contract to call
    uint256 value;       // Amount of ETH to pass with the call
    bytes data;          // calldata to pass
  }

  /**
   * @notice Allow wallet owner to execute an action
   * @param _txs        Transactions to process
   * @param _nonce      Signature nonce (may contain an encoded space)
   * @param _signature  Encoded signature
   */
  function execute(
    Transaction[] calldata _txs,
    uint256 _nonce,
    bytes calldata _signature
  ) external;

  /**
   * @notice Allow wallet to execute an action
   *   without signing the message
   * @param _txs  Transactions to execute
   */
  function selfExecute(
    Transaction[] calldata _txs
  ) external;
}


================================================
FILE: contracts/modules/commons/interfaces/IModuleCreator.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


interface IModuleCreator {
  error CreateFailed(bytes _code);

  /**
   * @notice Creates a contract forwarding eth value
   * @param _code Creation code of the contract
   * @return addr The address of the created contract
   */
  function createContract(bytes calldata _code) external payable returns (address addr);
}


================================================
FILE: contracts/modules/commons/interfaces/IModuleHooks.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


interface IModuleHooks {
  // Errors
  error HookAlreadyExists(bytes4 _signature);
  error HookDoesNotExist(bytes4 _signature);

  // Events
  event DefinedHook(bytes4 _signature, address _implementation);

  /**
   * @notice Reads the implementation hook of a signature
   * @param _signature Signature function
   * @return The address of the implementation hook, address(0) if none
  */
  function readHook(bytes4 _signature) external view returns (address);

  /**
   * @notice Adds a new hook to handle a given function selector
   * @param _signature Signature function linked to the hook
   * @param _implementation Hook implementation contract
   */
  function addHook(bytes4 _signature, address _implementation) external;

  /**
   * @notice Removes a registered hook
   * @param _signature Signature function linked to the hook
   */
  function removeHook(bytes4 _signature) external;
}


================================================
FILE: contracts/modules/commons/interfaces/IModuleUpdate.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


abstract contract IModuleUpdate {
  // Errors
  error InvalidImplementation(address _implementation);

  /**
   * @notice Updates the implementation of the base wallet
   * @param _implementation New main module implementation
   * @dev WARNING Updating the implementation can brick the wallet
   */
  function updateImplementation(address _implementation) external virtual;

  /**
   * @notice Updates the implementation of the base wallet, used internally.
   * @param _implementation New main module implementation
   * @dev WARNING Updating the implementation can brick the wallet
   */
  function _updateImplementation(address _implementation) internal virtual;
}


================================================
FILE: contracts/modules/commons/submodules/auth/SequenceBaseSig.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "../../../../utils/SignatureValidator.sol";
import "../../../../utils/LibBytesPointer.sol";
import "../../../../utils/LibBytes.sol";
import "../../../../utils/LibOptim.sol";


/**
 * @title SequenceBaseSig Library
 * @author Agustin Aguilar (aa@horizon.io)
 * @notice A Solidity implementation for handling signatures in the Sequence protocol.
 */
library SequenceBaseSig {
  using LibBytesPointer for bytes;

  uint256 internal constant FLAG_SIGNATURE = 0;
  uint256 internal constant FLAG_ADDRESS = 1;
  uint256 internal constant FLAG_DYNAMIC_SIGNATURE = 2;
  uint256 internal constant FLAG_NODE = 3;
  uint256 internal constant FLAG_BRANCH = 4;
  uint256 internal constant FLAG_SUBDIGEST = 5;
  uint256 internal constant FLAG_NESTED = 6;

  error InvalidNestedSignature(bytes32 _hash, address _addr, bytes _signature);
  error InvalidSignatureFlag(uint256 _flag);

  /**
  * @notice Generates a subdigest for the input digest (unique for this wallet and network).
  * @param _digest The input digest to generate the subdigest from.
  * @return bytes32 The subdigest generated from the input digest.
  */
  function subdigest(
    bytes32 _digest
  ) internal view returns (bytes32) {
    return keccak256(
      abi.encodePacked(
        "\x19\x01",
        block.chainid,
        address(this),
        _digest
      )
    );
  }

  /**
  * @notice Generates the leaf for an address and weight.
  * @dev The leaf is generated by concatenating the address and weight.
  *
  * @param _addr The address to generate the leaf for.
  * @param _weight The weight to generate the leaf for.
  * @return bytes32 The leaf generated from the address and weight.
  */
  function _leafForAddressAndWeight(
    address _addr,
    uint96 _weight
  ) internal pure returns (bytes32) {
    unchecked {
      return bytes32(uint256(_weight) << 160 | uint256(uint160(_addr)));
    }
  }

  /**
  * @notice Generates the leaf for a hardcoded subdigest.
  * @dev The leaf is generated by hashing 'Sequence static digest:\n' and the subdigest.
  * @param _subdigest The subdigest to generate the leaf for.
  * @return bytes32 The leaf generated from the hardcoded subdigest.
  */
  function _leafForHardcodedSubdigest(
    bytes32 _subdigest
  ) internal pure returns (bytes32) {
    return keccak256(abi.encodePacked('Sequence static digest:\n', _subdigest));
  }

  /**
  * @notice Generates the leaf for a nested tree node.
  * @dev The leaf is generated by hashing 'Sequence nested config:\n', the node, the threshold and the weight.
  *
  * @param _node The root of the node to generate the leaf for.
  * @param _threshold The internal threshold of the tree.
  * @param _weight The external weight of the tree.
  * @return bytes32 The leaf generated from the nested tree.
  */
  function _leafForNested(
    bytes32 _node,
    uint256 _threshold,
    uint256 _weight
  ) internal pure returns (bytes32) {
    return keccak256(abi.encodePacked('Sequence nested config:\n', _node, _threshold, _weight));
  }

  /**
   * @notice Returns the weight and root of a signature branch.
   * @dev If the signature contains a hardcoded subdigest, and it matches the input digest, then the weight is set to 2 ** 256 - 1.
   *
   * @param _subdigest The digest to verify the signature against.
   * @param _signature The signature branch to recover.
   * @return weight The total weight of the recovered signatures.
   * @return root The root hash of the recovered configuration.
   */
  function recoverBranch(
    bytes32 _subdigest,
    bytes calldata _signature
  ) internal view returns (
    uint256 weight,
    bytes32 root
  ) {
    unchecked {
      uint256 rindex;

      // Iterate until the image is completed
      while (rindex < _signature.length) {
        // Read next item type
        uint256 flag;
        (flag, rindex) = _signature.readUint8(rindex);

        if (flag == FLAG_ADDRESS) {
          // Read plain address
          uint8 addrWeight; address addr;
          (addrWeight, addr, rindex) = _signature.readUint8Address(rindex);

          // Write weight and address to image
          bytes32 node = _leafForAddressAndWeight(addr, addrWeight);
          root = root != bytes32(0) ? LibOptim.fkeccak256(root, node) : node;
          continue;
        }

        if (flag == FLAG_SIGNATURE) {
          // Read weight
          uint8 addrWeight;
          (addrWeight, rindex) = _signature.readUint8(rindex);

          // Read single signature and recover signer
          uint256 nrindex = rindex + 66;
          address addr = SignatureValidator.recoverSigner(_subdigest, _signature[rindex:nrindex]);
          rindex = nrindex;

          // Acumulate total weight of the signature
          weight += addrWeight;

          // Write weight and address to image
          bytes32 node = _leafForAddressAndWeight(addr, addrWeight);
          root = root != bytes32(0) ? LibOptim.fkeccak256(root, node) : node;
          continue;
        }

        if (flag == FLAG_DYNAMIC_SIGNATURE) {
          // Read signer and weight
          uint8 addrWeight; address addr;
          (addrWeight, addr, rindex) = _signature.readUint8Address(rindex);

          // Read signature size
          uint256 size;
          (size, rindex) = _signature.readUint24(rindex);

          // Read dynamic size signature
          uint256 nrindex = rindex + size;
          if (!SignatureValidator.isValidSignature(_subdigest, addr, _signature[rindex:nrindex])) {
            revert InvalidNestedSignature(_subdigest, addr, _signature[rindex:nrindex]);
          }
          rindex = nrindex;

          // Acumulate total weight of the signature
          weight += addrWeight;

          // Write weight and address to image
          bytes32 node = _leafForAddressAndWeight(addr, addrWeight);
          root = root != bytes32(0) ? LibOptim.fkeccak256(root, node) : node;
          continue;
        }

        if (flag == FLAG_NODE) {
          // Read node hash
          bytes32 node;
          (node, rindex) = _signature.readBytes32(rindex);
          root = root != bytes32(0) ? LibOptim.fkeccak256(root, node) : node;
          continue;
        }

        if (flag == FLAG_BRANCH) {
          // Enter a branch of the signature merkle tree
          uint256 size;
          (size, rindex) = _signature.readUint24(rindex);
          uint256 nrindex = rindex + size;

          uint256 nweight; bytes32 node;
          (nweight, node) = recoverBranch(_subdigest, _signature[rindex:nrindex]);

          weight += nweight;
          root = LibOptim.fkeccak256(root, node);

          rindex = nrindex;
          continue;
        }

        if (flag == FLAG_NESTED) {
          // Enter a branch of the signature merkle tree
          // but with an internal threshold and an external fixed weight
          uint256 externalWeight;
          (externalWeight, rindex) = _signature.readUint8(rindex);

          uint256 internalThreshold;
          (internalThreshold, rindex) = _signature.readUint16(rindex);

          uint256 size;
          (size, rindex) = _signature.readUint24(rindex);
          uint256 nrindex = rindex + size;

          uint256 internalWeight; bytes32 internalRoot;
          (internalWeight, internalRoot) = recoverBranch(_subdigest, _signature[rindex:nrindex]);
          rindex = nrindex;

          if (internalWeight >= internalThreshold) {
            weight += externalWeight;
          }

          bytes32 node = _leafForNested(internalRoot, internalThreshold, externalWeight);
          root = root != bytes32(0) ? LibOptim.fkeccak256(root, node) : node;

          continue;
        }

        if (flag == FLAG_SUBDIGEST) {
          // A hardcoded always accepted digest
          // it pushes the weight to the maximum
          bytes32 hardcoded;
          (hardcoded, rindex) = _signature.readBytes32(rindex);
          if (hardcoded == _subdigest) {
            weight = type(uint256).max;
          }

          bytes32 node = _leafForHardcodedSubdigest(hardcoded);
          root = root != bytes32(0) ? LibOptim.fkeccak256(root, node) : node;
          continue;
        }

        revert InvalidSignatureFlag(flag);
      }
    }
  }

  /**
   * @notice Returns the threshold, weight, root, and checkpoint of a signature.
   * @dev To verify the signature, the weight must be greater than or equal to the threshold, and the root
   *      must match the expected `imageHash` of the wallet.
   *
   * @param _subdigest The digest to verify the signature against.
   * @param _signature The signature to recover.
   * @return threshold The minimum weight required for the signature to be valid.
   * @return weight The total weight of the recovered signatures.
   * @return imageHash The root hash of the recovered configuration
   * @return checkpoint The checkpoint of the signature.
   */
  function recover(
    bytes32 _subdigest,
    bytes calldata _signature
  ) internal view returns (
    uint256 threshold,
    uint256 weight,
    bytes32 imageHash,
    uint256 checkpoint
  ) {
    unchecked {
      (weight, imageHash) = recoverBranch(_subdigest, _signature[6:]);

      // Threshold & checkpoint are the top nodes
      // (but they are first on the signature)
      threshold = LibBytes.readFirstUint16(_signature);
      checkpoint = LibBytes.readUint32(_signature, 2);

      imageHash = LibOptim.fkeccak256(imageHash, bytes32(threshold));
      imageHash = LibOptim.fkeccak256(imageHash, bytes32(checkpoint));
    }
  }
}


================================================
FILE: contracts/modules/commons/submodules/auth/SequenceChainedSig.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./SequenceBaseSig.sol";

import "../../interfaces/IModuleAuth.sol";

import "../../ModuleSelfAuth.sol";
import "../../ModuleStorage.sol";

import "../../../../utils/LibBytesPointer.sol";
import "../../../../utils/LibOptim.sol";

/**
 * @title Sequence chained auth recovery submodule
 * @author Agustin Aguilar (aa@horizon.io)
 * @notice Defines Sequence signatures that work by delegating control to new configurations.
 * @dev The delegations can be chained together, the first signature is the one that is used to validate
 *      the message, the last signature must match the current on-chain configuration of the wallet.
 */
abstract contract SequenceChainedSig is IModuleAuth, ModuleSelfAuth {
  using LibBytesPointer for bytes;

  bytes32 public constant SET_IMAGE_HASH_TYPE_HASH = keccak256("SetImageHash(bytes32 imageHash)");

  error LowWeightChainedSignature(bytes _signature, uint256 threshold, uint256 _weight);
  error WrongChainedCheckpointOrder(uint256 _current, uint256 _prev);

  /**
   * @notice Defined the special token that must be signed to delegate control to a new configuration.
   * @param _imageHash The hash of the new configuration.
   * @return bytes32 The message hash to be signed.
   */
  function _hashSetImageHashStruct(bytes32 _imageHash) internal pure returns (bytes32) {
    return LibOptim.fkeccak256(SET_IMAGE_HASH_TYPE_HASH, _imageHash);
  }

  /**
   * @notice Returns the threshold, weight, root, and checkpoint of a (chained) signature.
   * 
   * @dev This method return the `threshold`, `weight` and `imageHash` of the last signature in the chain.
   *      Intermediate signatures are validated directly in this method. The `subdigest` is the one of the
   *      first signature in the chain (since that's the one that is used to validate the message).
   *
   * @param _digest The digest to recover the signature from.
   * @param _signature The signature to recover.
   * @return threshold The threshold of the (last) signature.
   * @return weight The weight of the (last) signature.
   * @return imageHash The image hash of the (last) signature.
   * @return subdigest The subdigest of the (first) signature in the chain.
   * @return checkpoint The checkpoint of the (last) signature.
   */
  function chainedRecover(
    bytes32 _digest,
    bytes calldata _signature
  ) internal view returns (
    uint256 threshold,
    uint256 weight,
    bytes32 imageHash,
    bytes32 subdigest,
    uint256 checkpoint
  ) {
    uint256 rindex = 1;
    uint256 sigSize;

    //
    // First signature out of the loop
    //

    // First uint24 is the size of the signature
    (sigSize, rindex) = _signature.readUint24(rindex);
    uint256 nrindex = sigSize + rindex;

    (
      threshold,
      weight,
      imageHash,
      subdigest,
      checkpoint
    ) = signatureRecovery(
      _digest,
      _signature[rindex:nrindex]
    );

    if (weight < threshold) {
      revert LowWeightChainedSignature(_signature[rindex:nrindex], threshold, weight);
    }

    rindex = nrindex;

    // The following signatures are handled by this loop.
    // This is done this way because the first signature does not have a
    // checkpoint to be validated against.
    while (rindex < _signature.length) {
      // First uint24 is the size of the signature
      (sigSize, rindex) = _signature.readUint24(rindex);
      nrindex = sigSize + rindex;

      uint256 nextCheckpoint;

      (
        threshold,
        weight,
        imageHash,,
        // Do not change the subdigest;
        // it should remain that of the first signature.
        nextCheckpoint
      ) = signatureRecovery(
        _hashSetImageHashStruct(imageHash),
        _signature[rindex:nrindex]
      );

      // Validate signature
      if (weight < threshold) {
        revert LowWeightChainedSignature(_signature[rindex:nrindex], threshold, weight);
      }

      // Checkpoints must be provided in descending order
      // since the first signature is the one that is used to validate the message
      // and the last signature is the one that is used to validate the current configuration
      if (nextCheckpoint >= checkpoint) {
        revert WrongChainedCheckpointOrder(nextCheckpoint, checkpoint);
      }

      checkpoint = nextCheckpoint;
      rindex = nrindex;
    }
  }
}


================================================
FILE: contracts/modules/commons/submodules/auth/SequenceDynamicSig.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./SequenceBaseSig.sol";


library SequenceDynamicSig {

  /**
   * @notice Recover a "dynamically encoded" Sequence signature.
   * @dev The Signature is stripped of the first byte, which is the encoding flag.
   *
   * @param _subdigest The digest of the signature.
   * @param _signature The Sequence signature.
   * @return threshold The threshold weight required to validate the signature.
   * @return weight The weight of the signature.
   * @return imageHash The hash of the recovered configuration.
   * @return checkpoint The checkpoint of the configuration.
   */
  function recover(
    bytes32 _subdigest,
    bytes calldata _signature
  ) internal view returns (
    uint256 threshold,
    uint256 weight,
    bytes32 imageHash,
    uint256 checkpoint
  ) {
    return SequenceBaseSig.recover(_subdigest, _signature[1:]);
  }
}


================================================
FILE: contracts/modules/commons/submodules/auth/SequenceNoChainIdSig.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


library SequenceNoChainIdSig {

  /**
   * @notice Computes a subdigest for a Sequence signature that works on all chains.
   * @dev The subdigest is computed by removing the chain ID from the digest (using 0 instead).
   * @param _digest The digest of the chain of signatures.
   * @return bytes32 The subdigest with no chain ID.
   */
  function subdigest(bytes32 _digest) internal view returns (bytes32) {
    return keccak256(
      abi.encodePacked(
        "\x19\x01",
        uint256(0),
        address(this),
        _digest
      )
    );
  }
}


================================================
FILE: contracts/modules/commons/submodules/nonce/SubModuleNonce.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


library SubModuleNonce {
  // Nonce schema
  //
  // - space[160]:nonce[96]
  //
  uint256 internal constant NONCE_BITS = 96;
  bytes32 internal constant NONCE_MASK = bytes32(uint256(type(uint96).max));

  /**
   * @notice Decodes a raw nonce
   * @dev Schema: space[160]:type[96]
   * @param _rawNonce Nonce to be decoded
   * @return _space The nonce space of the raw nonce
   * @return _nonce The nonce of the raw nonce
   */
  function decodeNonce(uint256 _rawNonce) internal pure returns (
    uint256 _space,
    uint256 _nonce
  ) {
    unchecked {
      // Decode nonce
      _space = _rawNonce >> NONCE_BITS;
      _nonce = uint256(bytes32(_rawNonce) & NONCE_MASK);
    }
  }

  function encodeNonce(uint256 _space, uint256 _nonce) internal pure returns (uint256) {
    unchecked {
      // Combine space and nonce
      return (_space << NONCE_BITS) | _nonce;
    }
  }
}


================================================
FILE: contracts/modules/utils/GasEstimator.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


contract GasEstimator {
  function estimate(
    address _to,
    bytes calldata _data
  ) external returns (bool success, bytes memory result, uint256 gas) {
    // solhint-disable
    uint256 initialGas = gasleft();
    (success, result) = _to.call(_data);
    gas = initialGas - gasleft();
    // solhint-enable
  }
}


================================================
FILE: contracts/modules/utils/MultiCallUtils.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "../commons/interfaces/IModuleCalls.sol";


contract MultiCallUtils {
  // Errors
  error DelegateCallNotAllowed(uint256 _index);
  error CallReverted(uint256 _index, bytes _result);

  function multiCall(
    IModuleCalls.Transaction[] memory _txs
  ) public payable returns (
    bool[] memory _successes,
    bytes[] memory _results
  ) {
    _successes = new bool[](_txs.length);
    _results = new bytes[](_txs.length);

    for (uint256 i = 0; i < _txs.length; i++) {
      IModuleCalls.Transaction memory transaction = _txs[i];

      if (transaction.delegateCall) revert DelegateCallNotAllowed(i);
      if (gasleft() < transaction.gasLimit) revert IModuleCalls.NotEnoughGas(i, transaction.gasLimit, gasleft());

      // solhint-disable
      (_successes[i], _results[i]) = transaction.target.call{
        value: transaction.value,
        gas: transaction.gasLimit == 0 ? gasleft() : transaction.gasLimit
      }(transaction.data);
      // solhint-enable

      if (!_successes[i] && _txs[i].revertOnError) revert CallReverted(i, _results[i]);
    }
  }

  // ///
  // Globals
  // ///

  function callBlockhash(uint256 _i) external view returns (bytes32) {
    return blockhash(_i);
  }

  function callCoinbase() external view returns (address) {
    return block.coinbase;
  }

  function callDifficulty() external view returns (uint256) {
    return block.prevrandao; // old block.difficulty
  }

  function callPrevrandao() external view returns (uint256) {
    return block.prevrandao;
  }

  function callGasLimit() external view returns (uint256) {
    return block.gaslimit;
  }

  function callBlockNumber() external view returns (uint256) {
    return block.number;
  }

  function callTimestamp() external view returns (uint256) {
    return block.timestamp;
  }

  function callGasLeft() external view returns (uint256) {
    return gasleft();
  }

  function callGasPrice() external view returns (uint256) {
    return tx.gasprice;
  }

  function callOrigin() external view returns (address) {
    return tx.origin;
  }

  function callBalanceOf(address _addr) external view returns (uint256) {
    return _addr.balance;
  }

  function callCodeSize(address _addr) external view returns (uint256 size) {
    assembly { size := extcodesize(_addr) }
  }

  function callCode(address _addr) external view returns (bytes memory code) {
    assembly {
      let size := extcodesize(_addr)
      code := mload(0x40)
      mstore(0x40, add(code, and(add(add(size, 0x20), 0x1f), not(0x1f))))
      mstore(code, size)
      extcodecopy(_addr, add(code, 0x20), 0, size)
    }
  }

  function callCodeHash(address _addr) external view returns (bytes32 codeHash) {
    assembly { codeHash := extcodehash(_addr) }
  }

  function callChainId() external view returns (uint256 id) {
    assembly { id := chainid() }
  }
}


================================================
FILE: contracts/modules/utils/RequireUtils.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "../commons/ModuleNonce.sol";
import "../commons/submodules/nonce/SubModuleNonce.sol";

import "../../interfaces/tokens/IERC20.sol";
import "../../interfaces/tokens/IERC721.sol";
import "../../interfaces/tokens/IERC1155.sol";

contract RequireUtils {
  /**
   * @notice Validates that a given expiration hasn't expired
   * @dev Used as an optional transaction on a Sequence batch, to create expirable transactions.
   *
   * @param _expiration  Expiration to check
   */
  function requireNonExpired(uint256 _expiration) external view {
    require(block.timestamp < _expiration, "RequireUtils#requireNonExpired: EXPIRED");
  }

  /**
   * @notice Validates that a given wallet has reached a given nonce
   * @dev Used as an optional transaction on a Sequence batch, to define transaction execution order
   *
   * @param _wallet Sequence wallet
   * @param _nonce  Required nonce
   */
  function requireMinNonce(address _wallet, uint256 _nonce) external view {
    (uint256 space, uint256 nonce) = SubModuleNonce.decodeNonce(_nonce);
    uint256 currentNonce = ModuleNonce(_wallet).readNonce(space);
    require(currentNonce >= nonce, "RequireUtils#requireMinNonce: NONCE_BELOW_REQUIRED");
  }

  /**
   * @notice Validates that a wallet has a minimum ERC20 token balance
   * @param _token ERC20 token address
   * @param _wallet Sequence wallet
   * @param _minBalance Minimum required balance
   */
  function requireMinERC20Balance(address _token, address _wallet, uint256 _minBalance) external view {
    uint256 balance = IERC20(_token).balanceOf(_wallet);
    require(balance >= _minBalance, 'RequireUtils#requireMinERC20Balance: BALANCE_TOO_LOW');
  }

  /**
   * @notice Validates that a wallet has a minimum ERC20 allowance for a spender
   * @param _token ERC20 token address
   * @param _owner Sequence wallet
   * @param _spender Address allowed to spend the tokens
   * @param _minAllowance Minimum required allowance
   */
  function requireMinERC20Allowance(address _token, address _owner, address _spender, uint256 _minAllowance) external view {
    uint256 allowance = IERC20(_token).allowance(_owner, _spender);
    require(allowance >= _minAllowance, 'RequireUtils#requireMinERC20Allowance: ALLOWANCE_TOO_LOW');
  }

  /**
   * @notice Validates that a wallet owns a specific ERC721 token
   * @param _token ERC721 token address
   * @param _wallet Sequence wallet
   * @param _tokenId Token ID to check for ownership
   */
  function requireERC721Ownership(address _token, address _wallet, uint256 _tokenId) external view {
    address owner = IERC721(_token).ownerOf(_tokenId);
    require(owner == _wallet, 'RequireUtils#requireERC721Ownership: NOT_OWNER');
  }

  /**
   * @notice Validates that an ERC721 token is approved for a specific spender
   * @param _token ERC721 token address
   * @param _owner Sequence wallet
   * @param _spender Address that should have approval
   * @param _tokenId Token ID to check for approval
   */
  function requireERC721Approval(address _token, address _owner, address _spender, uint256 _tokenId) external view {
    address approved = IERC721(_token).getApproved(_tokenId);
    require(
      approved == _spender || IERC721(_token).isApprovedForAll(_owner, _spender),
      'RequireUtils#requireERC721Approval: NOT_APPROVED'
    );
  }

  /**
   * @notice Validates that a wallet has a minimum balance of an ERC1155 token
   * @param _token ERC1155 token address
   * @param _wallet Sequence wallet
   * @param _tokenId Token ID to check
   * @param _minBalance Minimum required balance
   */
  function requireMinERC1155Balance(address _token, address _wallet, uint256 _tokenId, uint256 _minBalance) external view {
    uint256 balance = IERC1155(_token).balanceOf(_wallet, _tokenId);
    require(balance >= _minBalance, 'RequireUtils#requireMinERC1155Balance: BALANCE_TOO_LOW');
  }

  /**
   * @notice Validates that an ERC1155 token is approved for a specific operator
   * @param _token ERC1155 token address
   * @param _owner Sequence wallet
   * @param _operator Address that should have operator approval
   */
  function requireERC1155Approval(address _token, address _owner, address _operator) external view {
    bool isApproved = IERC1155(_token).isApprovedForAll(_owner, _operator);
    require(isApproved, 'RequireUtils#requireERC1155Approval: NOT_APPROVED');
  }
}


================================================
FILE: contracts/modules/utils/SequenceUtils.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./MultiCallUtils.sol";
import "./RequireUtils.sol";


contract SequenceUtils is
  MultiCallUtils,
  RequireUtils
{ }


================================================
FILE: contracts/trust/Trust.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "../interfaces/IERC1271Wallet.sol";
import "../utils/SignatureValidator.sol";

function absDiff(uint256 a, uint256 b) pure returns (bool, uint256) {
  if (a > b) {
    return (true, a - b);
  }

  return (false, b - a);
}

contract Trust is IERC1271Wallet {
  error UnlockInThePast(uint256 _unlocksAt, uint256 _elapsed);
  error UnlockTooEarly(uint256 _unlocksAt, uint256 _diff);

  error NotOwner(address _sender);
  error NotUnlocked(uint256 _unlocksAt);
  error FailedTransaction(address payable _to, uint256 _value, bytes _data, bytes _result);

  error EmptySignature();
  error InvalidSignatureFlag(bytes _signature, bytes1 _flag);
  error InvalidSignature(bytes32 _hash, bytes32 _rehash, address _signer, bytes _signature);

  event SetUnlocksAt(uint256 _unlocksAt);
  event SentTransaction(address payable _to, uint256 _value, bytes _data, bytes _result);

  address immutable public owner;
  address immutable public beneficiary;
  uint256 immutable public duration;

  uint256 public unlocksAt = type(uint256).max;

  constructor (
    address _owner,
    address _beneficiary,
    uint256 _duration
  ) {
    owner = _owner;
    beneficiary = _beneficiary;
    duration = _duration;
  }

  modifier onlyAllowed() {
    if (msg.sender != owner) {
      if (msg.sender != beneficiary) {
        revert NotOwner(msg.sender);
      }

      if (isLocked()) {
        revert NotUnlocked(unlocksAt);
      }
    }

    _;
  }

  modifier onlyMember() {
    if (msg.sender != owner && msg.sender != beneficiary) {
      revert NotOwner(msg.sender);
    }

    _;
  }

  function isLocked() public view returns (bool) {
    return block.timestamp < unlocksAt;
  }

  function setUnlocksAt(uint256 _unlocksAt) external onlyMember {
    // Diff between the current time and the unlock time must be
    // greater than the duration of the trust
    (bool isPast, uint256 elapsed) = absDiff(block.timestamp, _unlocksAt);
    if (isPast) {
      revert UnlockInThePast(_unlocksAt, elapsed);
    }

    if (elapsed < duration) {
      revert UnlockTooEarly(_unlocksAt, elapsed);
    }

    emit SetUnlocksAt(_unlocksAt);
    unlocksAt = _unlocksAt;
  }

  function sendTransaction(
    address payable _to,
    uint256 _value,
    bytes calldata _data
  ) external onlyAllowed returns (bytes memory) {
    (bool success, bytes memory result) = _to.call{value: _value}(_data);

    if (!success) {
      revert FailedTransaction(_to, _value, _data, result);
    }

    emit SentTransaction(_to, _value, _data, result);
    return result;
  }

  bytes4 internal constant SELECTOR_ERC1271_BYTES_BYTES = 0x20c13b0b;
  bytes4 internal constant SELECTOR_ERC1271_BYTES32_BYTES = 0x1626ba7e;

  function isValidSignature(
    bytes calldata _data,
    bytes calldata _signature
  ) external view returns (bytes4) {
    bytes4 res = Trust(payable(address((this)))).isValidSignature(
      keccak256(_data),
      _signature
    );

    assert(res == SELECTOR_ERC1271_BYTES32_BYTES);
    return SELECTOR_ERC1271_BYTES_BYTES;
  }

  function isValidSignature(
    bytes32 _hash,
    bytes calldata _signature
  ) external view returns (bytes4) {
    if (_signature.length == 0) {
      revert EmptySignature();
    }

    // The last byte determines how the signature is going to be interpreted
    // 0x00 -> Signed by the owner
    // 0x01 -> Signed by the beneficiary
    // 0x02 -> Signed by the owner for any network
    // 0x03 -> Signed by the beneficiary for any network
    address signer;
    uint256 chainId;

    {
      bytes1 flag = _signature[_signature.length - 1];

      if (flag == 0x00) {
        signer = owner;
        chainId = block.chainid;
      } else if (flag == 0x01) {
        signer = beneficiary;
        chainId = block.chainid;
      } else if (flag == 0x02) {
        signer = owner;
        chainId = 0;
      } else if (flag == 0x03) {
        signer = beneficiary;
        chainId = 0;
      } else {
        revert InvalidSignatureFlag(_signature, flag);
      }
    }

    if (signer != owner && isLocked()) {
      revert NotUnlocked(unlocksAt);
    }

    // Re-hash the hash adding the address of the trust
    // otherwise the signature will be valid for any trust
    bytes32 rehash = keccak256(abi.encode(address(this), _hash, chainId));

    // Validate the signature
    if (!SignatureValidator.isValidSignature(rehash, signer, _signature[0:_signature.length - 1])) {
      revert InvalidSignature(_hash, rehash, signer, _signature[0:_signature.length - 1]);
    }

    return SELECTOR_ERC1271_BYTES32_BYTES;
  }

  receive() external payable {}
  fallback() external payable {}
}


================================================
FILE: contracts/trust/TrustFactory.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "./Trust.sol";


contract TrustFactory {
  function trustCreationCode() external pure returns (bytes memory) {
    return type(Trust).creationCode;
  }

  function addressOf(
    address _owner,
    address _beneficiary,
    uint256 _duration
  ) external view returns (address) {
    return address(uint160(uint(keccak256(abi.encodePacked(
      bytes1(0xff),
      address(this),
      bytes32(0),
      keccak256(abi.encodePacked(
        type(Trust).creationCode,
        abi.encode(_owner, _beneficiary, _duration)
      ))
    )))));
  }

  function deploy(
    address _owner,
    address _beneficiary,
    uint256 _duration
  ) external returns (Trust) {
    return new Trust{ salt: bytes32(0) }( _owner, _beneficiary, _duration);
  }
}


================================================
FILE: contracts/utils/LibAddress.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


library LibAddress {
  /**
   * @notice Will return true if provided address is a contract
   * @param account Address to verify if contract or not
   * @dev This contract will return false if called within the constructor of
   *      a contract's deployment, as the code is not yet stored on-chain.
   */
  function isContract(address account) internal view returns (bool) {
    uint256 csize;
    // solhint-disable-next-line no-inline-assembly
    assembly { csize := extcodesize(account) }
    return csize != 0;
  }
}


================================================
FILE: contracts/utils/LibBytes.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


/**
 * @title Library for reading data from bytes arrays
 * @author Agustin Aguilar (aa@horizon.io)
 * @notice This library contains functions for reading data from bytes arrays.
 *
 * @dev These functions do not check if the input index is within the bounds of the data array.
 *         Reading out of bounds may return dirty values.
 */
library LibBytes {

  /**
   * @notice Returns the bytes32 value at the given index in the input data.
   * @param data The input data.
   * @param index The index of the value to retrieve.
   * @return a The bytes32 value at the given index.
   */
  function readBytes32(
    bytes calldata data,
    uint256 index
  ) internal pure returns (
    bytes32 a
  ) {
    assembly {
      a := calldataload(add(data.offset, index))
    }
  }

  /**
   * @notice Returns the uint8 value at the given index in the input data.
   * @param data The input data.
   * @param index The index of the value to retrieve.
   * @return a The uint8 value at the given index.
   */
  function readUint8(
    bytes calldata data,
    uint256 index
  ) internal pure returns (
    uint8 a
  ) {
    assembly {
      let word := calldataload(add(index, data.offset))
      a := shr(248, word)
    }
  }

  /**
   * @notice Returns the first uint16 value in the input data.
   * @param data The input data.
   * @return a The first uint16 value in the input data.
   */
  function readFirstUint16(
    bytes calldata data
  ) internal pure returns (
    uint16 a
  ) {
    assembly {
      let word := calldataload(data.offset)
      a := shr(240, word)
    }
  }

  /**
   * @notice Returns the uint32 value at the given index in the input data.
   * @param data The input data.
   * @param index The index of the value to retrieve.
   * @return a The uint32 value at the given index.
   */
  function readUint32(
    bytes calldata data,
    uint256 index
  ) internal pure returns (
    uint32 a
  ) {
    assembly {
      let word := calldataload(add(index, data.offset))
      a := shr(224, word)
    }
  }

  function readMBytes4(
    bytes memory data,
    uint256 index
  ) internal pure returns (
    bytes4 a
  ) {
    assembly {
      let word := mload(add(add(data, 0x20), index))
      a := and(word, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
    }
  }

  function readMBytes32(
    bytes memory data,
    uint256 index
  ) internal pure returns (
    bytes32 a
  ) {
    assembly {
      a := mload(add(add(data, 0x20), index))
    }
  }
}


================================================
FILE: contracts/utils/LibBytesPointer.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;


/**
 * @title Library for reading data from bytes arrays with a pointer
 * @author Agustin Aguilar (aa@horizon.io)
 * @notice This library contains functions for reading data from bytes arrays with a pointer.
 *
 * @dev These functions do not check if the input index is within the bounds of the data array.
 *         Reading out of bounds may return dirty values.
 */
library LibBytesPointer {

  /**
   * @dev Returns the first uint16 value in the input data and updates the pointer.
   * @param _data The input data.
   * @return a The first uint16 value.
   * @return newPointer The new pointer.
   */
  function readFirstUint16(
    bytes calldata _data
  ) internal pure returns (
    uint16 a,
    uint256 newPointer
  ) {
    assembly {
      let word := calldataload(_data.offset)
      a := shr(240, word)
      newPointer := 2
    }
  }

  /**
   * @notice Returns the uint8 value at the given index in the input data and updates the pointer.
   * @param _data The input data.
   * @param _index The index of the value to retrieve.
   * @return a The uint8 value at the given index.
   * @return newPointer The new pointer.
   */
  function readUint8(
    bytes calldata _data,
    uint256 _index
  ) internal pure returns (
    uint8 a,
    uint256 newPointer
  ) {
    assembly {
      let word := calldataload(add(_index, _data.offset))
      a := shr(248, word)
      newPointer := add(_index, 1)
    }
  }

  function readAddress(
    bytes calldata _data,
    uint256 _index
  ) internal pure returns (
    address a,
    uint256 newPointer
  ) {
    assembly {
      let word := calldataload(add(_index, _data.offset))
      a := and(shr(96, word), 0xffffffffffffffffffffffffffffffffffffffff)
      newPointer := add(_index, 20)
    }
  }

  /**
   * @notice Returns the uint8 value and the address at the given index in the input data and updates the pointer.
   * @param _data The input data.
   * @param _index The index of the value to retrieve.
   * @return a The uint8 value at the given index.
   * @return b The following address value.
   * @return newPointer The new pointer.
   */
  function readUint8Address(
    bytes calldata _data,
    uint256 _index
  ) internal pure returns (
    uint8 a,
    address b,
    uint256 newPointer
  ) {
    assembly {
      let word := calldataload(add(_index, _data.offset))
      a := shr(248, word)
      b := and(shr(88, word), 0xffffffffffffffffffffffffffffffffffffffff)
      newPointer := add(_index, 21)
    }
  }

  /**
   * @notice Returns the uint16 value at the given index in the input data and updates the pointer.
   * @param _data The input data.
   * @param _index The index of the value to retrieve.
   * @return a The uint16 value at the given index.
   * @return newPointer The new pointer.
   */
  function readUint16(
    bytes calldata _data,
    uint256 _index
  ) internal pure returns (
    uint16 a,
    uint256 newPointer
  ) {
    assembly {
      let word := calldataload(add(_index, _data.offset))
      a := and(shr(240, word), 0xffff)
      newPointer := add(_index, 2)
    }
  }

  function readUintX(
    bytes calldata _data,
    uint256 _bytes,
    uint256 _index
  ) internal pure returns (
    uint256 a,
    uint256 newPointer
  ) {
    assembly {
      let word := calldataload(add(_index, _data.offset))
      let shift := sub(256, mul(_bytes, 8))
      a := and(shr(shift, word), sub(shl(mul(8, _bytes), 1), 1))
      newPointer := add(_index, _bytes)
    }
  }

  /**
   * @notice Returns the uint24 value at the given index in the input data and updates the pointer.
   * @param _data The input data.
   * @param _index The index of the value to retrieve.
   * @return a The uint24 value at the given index.
   * @return newPointer The new pointer.
   */
  function readUint24(
    bytes calldata _data,
    uint256 _index
  ) internal pure returns (
    uint24 a,
    uint256 newPointer
  ) {
    assembly {
      let word := calldataload(add(_index, _data.offset))
      a := and(shr(232, word), 0xffffff)
      newPointer := add(_index, 3)
    }
  }

  /**
   * @notice Returns the uint64 value at the given index in the input data and updates the pointer.
   * @param _data The input data.
   * @param _index The index of the value to retrieve.
   * @return a The uint64 value at the given index.
   * @return newPointer The new pointer.
   */
  function readUint64(
    bytes calldata _data,
    uint256 _index
  ) internal pure returns (
    uint64 a,
    uint256 newPointer
  ) {
    assembly {
      let word := calldataload(add(_index, _data.offset))
      a := and(shr(192, word), 0xffffffffffffffff)
      newPointer := add(_index, 8)
    }
  }

  function readBytes4(
    bytes calldata _data,
    uint256 _pointer
  ) internal pure returns (
    bytes4 a,
    uint256 newPointer
  ) {
    assembly {
      a := calldataload(add(_pointer, _data.offset))
      a := and(a, 0xFFFFFFFF00000000000000000000000000000000000000000000000000000000)
      newPointer := add(_pointer, 4)
    }
  }

  /**
   * @notice Returns the bytes32 value at the given index in the input data and updates the pointer.
   * @param _data The input data.
   * @param _pointer The index of the value to retrieve.
   * @return a The bytes32 value at the given index.
   * @return newPointer The new pointer.
   */
  function readBytes32(
    bytes calldata _data,
    uint256 _pointer
  ) internal pure returns (
    bytes32 a,
    uint256 newPointer
  ) {
    assembly {
      a := calldataload(add(_pointer, _data.offset))
      newPointer := add(_pointer, 32)
    }
  }
}


================================================
FILE: contracts/utils/LibOptim.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

/**
 * @title Library for optimized EVM operations
 * @author Agustin Aguilar (aa@horizon.io)
 * @notice This library contains functions for optimizing certain EVM operations.
 */
library LibOptim {

  /**
   * @notice Computes the keccak256 hash of two 32-byte inputs.
   * @dev It uses only scratch memory space.
   * @param _a The first 32 bytes of the hash.
   * @param _b The second 32 bytes of the hash.
   * @return c The keccak256 hash of the two 32-byte inputs.
   */
  function fkeccak256(
    bytes32 _a,
    bytes32 _b
  ) internal pure returns (bytes32 c) {
    assembly {
      mstore(0, _a)
      mstore(32, _b)
      c := keccak256(0, 64)
    }
  }

  /**
   * @notice Returns the return data from the last call.
   * @return r The return data from the last call.
   */
  function returnData() internal pure returns (bytes memory r) {
    assembly {
      let size := returndatasize()
      r := mload(0x40)
      let start := add(r, 32)
      mstore(0x40, add(start, size))
      mstore(r, size)
      returndatacopy(start, 0, size)
    }
  }

  /**
   * @notice Calls another contract with the given parameters.
   * @dev This method doesn't increase the memory pointer.
   * @param _to The address of the contract to call.
   * @param _val The value to send to the contract.
   * @param _gas The amount of gas to provide for the call.
   * @param _data The data to send to the contract.
   * @return r The success status of the call.
   */
  function call(
    address _to,
    uint256 _val,
    uint256 _gas,
    bytes calldata _data
  ) internal returns (bool r) {
    assembly {
      let tmp := mload(0x40)
      calldatacopy(tmp, _data.offset, _data.length)

      r := call(
        _gas,
        _to,
        _val,
        tmp,
        _data.length,
        0,
        0
      )
    }
  }

  /**
   * @notice Calls another contract with the given parameters, using delegatecall.
   * @dev This method doesn't increase the memory pointer.
   * @param _to The address of the contract to call.
   * @param _gas The amount of gas to provide for the call.
   * @param _data The data to send to the contract.
   * @return r The success status of the call.
   */
  function delegatecall(
    address _to,
    uint256 _gas,
    bytes calldata _data
  ) internal returns (bool r) {
    assembly {
      let tmp := mload(0x40)
      calldatacopy(tmp, _data.offset, _data.length)

      r := delegatecall(
        _gas,
        _to,
        tmp,
        _data.length,
        0,
        0
      )
    }
  }
}


================================================
FILE: contracts/utils/LibString.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

/**
 * @title Library for string manipulation operations
 * @notice This library contains functions for manipulating strings in Solidity.
 */
library LibString {
  bytes private constant ALPHABET_HEX_16 = '0123456789abcdef';
  bytes private constant ALPHABET_32 = 'abcdefghijklmnopqrstuvwxyz234567';

  /**
   * @notice Prefixes a hexadecimal string with "0x".
   * @param _hex The hexadecimal string to prefix.
   * @return The prefixed hexadecimal string.
   */
  function prefixHexadecimal(string memory _hex) internal pure returns (string memory) {
    return string(abi.encodePacked('0x', _hex));
  }

  /**
   * @notice Prefixes a base32 string with "b".
   * @param _base32 The base32 string to prefix.
   * @return The prefixed base32 string.
   */
  function prefixBase32(string memory _base32) internal pure returns (string memory) {
    return string(abi.encodePacked('b', _base32));
  }

  /**
   * @notice Converts a byte array to a hexadecimal string.
   * @param _bytes The byte array to convert.
   * @return The resulting hexadecimal string.
   */
  function bytesToHexadecimal(bytes memory _bytes) internal pure returns (string memory) {
    uint256 bytesLength = _bytes.length;
    bytes memory bytesArray = new bytes(bytesLength << 1);

    unchecked {
      for (uint256 i = 0; i < bytesLength; i++) {
        uint256 word = uint8(_bytes[i]);
        uint256 ib = i << 1;
        bytesArray[ib] = bytes1(ALPHABET_HEX_16[word >> 4]);
        bytesArray[ib + 1] = bytes1(ALPHABET_HEX_16[word & 0xf]);
      }
    }

    return string(bytesArray);
  }

  /**
   * @notice Converts a byte array to a base32 string.
   * @param _bytes The byte array to convert.
   * @return The resulting base32 string.
   */
  function bytesToBase32(bytes memory _bytes) internal pure returns (string memory) {
    uint256 bytesLength = _bytes.length;

    uint256 t1 = bytesLength << 3;

    unchecked {
      // base32-encoded length = ceil(# of bits / 5)
      bytes memory bytesArray = new bytes((t1 + 4) / 5);

      uint256 bits = 0;
      uint256 buffer = 0;
      uint256 pointer = 0;

      for (uint256 i = 0; i < bytesLength; i++) {
        buffer = (buffer << 8) | uint8(_bytes[i]);
        bits += 8;

        while (bits >= 5) {
          bits -= 5;
          bytesArray[pointer] = bytes1(ALPHABET_32[(buffer >> bits) & 0x1f]);
          pointer++;
        }
      }

      if (bits > 0) {
        bytesArray[pointer] = bytes1(ALPHABET_32[(buffer << (5 - bits)) & 0x1f]);
      }

      return string(bytesArray);
    }
  }
}


================================================
FILE: contracts/utils/SignatureValidator.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "../interfaces/IERC1271Wallet.sol";

import "./LibBytes.sol";

/**
 * @dev Contains logic for signature validation.
 * Signatures from wallet contracts assume ERC-1271 support (https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1271.md)
 * Notes: Methods are strongly inspired by contracts in https://github.com/0xProject/0x-monorepo/blob/development/
 */
library SignatureValidator {
  // Errors
  error InvalidSignatureLength(bytes _signature);
  error EmptySignature();
  error InvalidSValue(bytes _signature, bytes32 _s);
  error InvalidVValue(bytes _signature, uint256 _v);
  error UnsupportedSignatureType(bytes _signature, uint256 _type, bool _recoverMode);
  error SignerIsAddress0(bytes _signature);

  using LibBytes for bytes;

  /***********************************|
  |             Variables             |
  |__________________________________*/

  // bytes4(keccak256("isValidSignature(bytes,bytes)"))
  bytes4 constant internal ERC1271_MAGICVALUE = 0x20c13b0b;

  // bytes4(keccak256("isValidSignature(bytes32,bytes)"))
  bytes4 constant internal ERC1271_MAGICVALUE_BYTES32 = 0x1626ba7e;

  // Allowed signature types.
  uint256 private constant SIG_TYPE_EIP712 = 1;
  uint256 private constant SIG_TYPE_ETH_SIGN = 2;
  uint256 private constant SIG_TYPE_WALLET_BYTES32 = 3;

  /***********************************|
  |        Signature Functions        |
  |__________________________________*/

 /**
   * @notice Recover the signer of hash, assuming it's an EOA account
   * @dev Only for SignatureType.EIP712 and SignatureType.EthSign signatures
   * @param _hash      Hash that was signed
   *   encoded as (bytes32 r, bytes32 s, uint8 v, ... , SignatureType sigType)
   */
  function recoverSigner(
    bytes32 _hash,
    bytes calldata _signature
  ) internal pure returns (address signer) {
    if (_signature.length != 66) revert InvalidSignatureLength(_signature);
    uint256 signatureType = _signature.readUint8(_signature.length - 1);

    // Variables are not scoped in Solidity.
    uint8 v = _signature.readUint8(64);
    bytes32 r = _signature.readBytes32(0);
    bytes32 s = _signature.readBytes32(32);

    // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
    // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
    // the valid range for s in (281): 0 < s < secp256k1n ÷ 2 + 1, and for v in (282): v ∈ {27, 28}. Most
    // signatures from current libraries generate a unique signature with an s-value in the lower half order.
    //
    // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
    // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
    // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
    // these malleable signatures as well.
    //
    // Source OpenZeppelin
    // https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/cryptography/ECDSA.sol

    if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
      revert InvalidSValue(_signature, s);
    }

    if (v != 27 && v != 28) {
      revert InvalidVValue(_signature, v);
    }

    // Signature using EIP712
    if (signatureType == SIG_TYPE_EIP712) {
      signer = ecrecover(_hash, v, r, s);

    // Signed using web3.eth_sign() or Ethers wallet.signMessage()
    } else if (signatureType == SIG_TYPE_ETH_SIGN) {
      signer = ecrecover(
        keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash)),
        v,
        r,
        s
      );

    } else {
      // We cannot recover the signer for any other signature type.
      revert UnsupportedSignatureType(_signature, signatureType, true);
    }

    // Prevent signer from being 0x0
    if (signer == address(0x0)) revert SignerIsAddress0(_signature);

    return signer;
  }

 /**
   * @notice Returns true if the provided signature is valid for the given signer.
   * @dev Supports SignatureType.EIP712, SignatureType.EthSign, and ERC1271 signatures
   * @param _hash      Hash that was signed
   * @param _signer    Address of the signer candidate
   * @param _signature Signature byte array
   */
  function isValidSignature(
    bytes32 _hash,
    address _signer,
    bytes calldata _signature
  ) internal view returns (bool valid) {
    if (_signature.length == 0) {
      revert EmptySignature();
    }

    uint256 signatureType = uint8(_signature[_signature.length - 1]);
    if (signatureType == SIG_TYPE_EIP712 || signatureType == SIG_TYPE_ETH_SIGN) {
      // Recover signer and compare with provided
      valid = recoverSigner(_hash, _signature) == _signer;

    } else if (signatureType == SIG_TYPE_WALLET_BYTES32) {
      // Remove signature type before calling ERC1271, restore after call
      valid = ERC1271_MAGICVALUE_BYTES32 == IERC1271Wallet(_signer).isValidSignature(_hash, _signature[0:_signature.length - 1]);

    } else {
      // We cannot validate any other signature type.
      // We revert because we can say nothing about its validity.
      revert UnsupportedSignatureType(_signature, signatureType, false);
    }
  }
}


================================================
FILE: foundry.toml
================================================
[profile.default]
src = 'contracts'
out = 'foundry_artifacts'
libs = ["node_modules", "lib"]
test = 'foundry_test'

ffi = true
max_test_rejects = 2048000


================================================
FILE: foundry_test/base/AdvTest.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "forge-std/Test.sol";


contract AdvTest is Test {
  function signAndPack(uint256 _pk, bytes32 _hash) internal pure returns (bytes memory) {
    (uint8 v, bytes32 r, bytes32 s) = vm.sign(_pk, _hash);
    return abi.encodePacked(r, s, v);
  }

  function signAndPack(uint256 _pk, bytes32 _hash, uint8 _sufix) internal pure returns (bytes memory) {
    (uint8 v, bytes32 r, bytes32 s) = vm.sign(_pk, _hash);
    return abi.encodePacked(r, s, v, _sufix);
  }

  function mayBoundArr(uint256 _size) internal view returns (uint256) {
    try vm.envUint('MAX_ARRAY_LEN') returns (uint256 b) {
      return b == 0 ? _size : bound(_size, 0, b);
    } catch {
      return _size;
    }
  }

  function boundNoSys(address _a) internal view returns (address) {
    address c2 = address(0x007109709ecfa91a80626ff3989d68f67f5b1dd12d);
    address vm = address(0x004e59b44847b379578588920ca78fbf26c0b4956c);
    address c3 = address(0x00000000000000000000636f6e736f6c652e6c6f67);

    boundNoPrecompile(_a);
    boundDiff(_a, c2, vm, c3, address(this));

    return _a;
  }

  function boundNoPrecompile(address _a) internal pure returns (address) {
    vm.assume(uint160(_a)> 10);
    return _a;
  }

  function boundDiff(address _a, address _b) internal pure returns (address) {
    vm.assume(_a != _b);
    return _a;
  }

  function boundDiff(address _a, address _b, address _c) internal pure returns (address) {
    address[] memory arr = new address[](2);
    arr[0] = _b;
    arr[1] = _c;
    return boundDiff(_a, arr);
  }

  function boundDiff(address _a, address _b, address _c, address _d) internal pure returns (address) {
    address[] memory _arr = new address[](3);
    _arr[0] = _b;
    _arr[1] = _c;
    _arr[2] = _d;
    return boundDiff(_a, _arr);
  }

  function boundDiff(address _a, address _b, address _c, address _d, address _e) internal pure returns (address) {
    address[] memory _arr = new address[](4);
    _arr[0] = _b;
    _arr[1] = _c;
    _arr[2] = _d;
    _arr[3] = _e;
    return boundDiff(_a, _arr);
  }

  function boundDiff(address _a, address[] memory _b) internal pure returns (address) {
    vm.assume(!inSet(_a, _b));
    return _a;
  }

  function boundPk(uint256 _a) internal view returns (uint256) {
    _a = bound(_a, 1, 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364139);
    return _a;
  }

  function boundDiff(uint256 _a, uint256 _b) internal pure returns (uint256) {
    vm.assume(_a != _b);
    return _a;
  }

  function boundDiff(uint256 _a, uint256 _b, uint256 _c) internal pure returns (uint256) {
    uint256[] memory arr = new uint256[](2);
    arr[0] = _b;
    arr[1] = _c;
    return boundDiff(_a, arr);
  }

  function boundDiff(uint256 _a, uint256 _b, uint256 _c, uint256 _d) internal pure returns (uint256) {
    uint256[] memory _arr = new uint256[](3);
    _arr[0] = _b;
    _arr[1] = _c;
    _arr[2] = _d;
    return boundDiff(_a, _arr);
  }

  function boundDiff(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e) internal pure returns (uint256) {
    uint256[] memory _arr = new uint256[](4);
    _arr[0] = _b;
    _arr[1] = _c;
    _arr[2] = _d;
    _arr[3] = _e;
    return boundDiff(_a, _arr);
  }

  function boundDiff(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e, uint256 _f) internal pure returns (uint256) {
    uint256[] memory _arr = new uint256[](5);
    _arr[0] = _b;
    _arr[1] = _c;
    _arr[2] = _d;
    _arr[3] = _e;
    _arr[4] = _f;
    return boundDiff(_a, _arr);
  }

  function boundDiff(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e, uint256 _f, uint256 _g) internal pure returns (uint256) {
    uint256[] memory _arr = new uint256[](6);
    _arr[0] = _b;
    _arr[1] = _c;
    _arr[2] = _d;
    _arr[3] = _e;
    _arr[4] = _f;
    _arr[5] = _g;
    return boundDiff(_a, _arr);
  }

  function boundDiff(uint256 _a, uint256 _b, uint256 _c, uint256 _d, uint256 _e, uint256 _f, uint256 _g, uint256 _h) internal pure returns (uint256) {
    uint256[] memory _arr = new uint256[](7);
    _arr[0] = _b;
    _arr[1] = _c;
    _arr[2] = _d;
    _arr[3] = _e;
    _arr[4] = _f;
    _arr[5] = _g;
    _arr[6] = _h;
    return boundDiff(_a, _arr);
  }

  function boundDiff(uint256 _a, uint256[] memory _b) internal pure returns (uint256) {
    vm.assume(!inSet(_a, _b));
    return _a;
  }

  function inSet(uint256 _a, uint256[] memory _b) internal pure returns (bool) {
    unchecked {
      for (uint256 i = 0; i < _b.length; i++) {
        if (_a == _b[i]) {
          return true;
        }
      }

      return false;
    }
  }

  function inSet(address _a, address[] memory _b) internal pure returns (bool) {
    unchecked {
      for (uint256 i = 0; i < _b.length; i++) {
        if (_a == _b[i]) {
          return true;
        }
      }

      return false;
    }
  }

  function boundNoContract(address _a) internal view returns (address) {
    vm.assume(_a.code.length == 0);
    return _a;
  }

  function boundNoBalance(address _a) internal view returns (address) {
    vm.assume(_a.balance == 0);
    return _a;
  }

  function replicate(bytes memory _data) internal {
    (bool suc, bytes memory res) = address(this).call(_data);
    if (!suc) {
      assembly {
        revert(add(res, 32), mload(res))
      }
    }
  }

  function addrToBytes32(address _addr) internal pure returns (bytes32) {
    return bytes32(uint256(uint160(_addr)));
  }
}


================================================
FILE: foundry_test/hooks/WalletProxyHook.t.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import 'contracts/hooks/WalletProxyHook.sol';
import 'contracts/hooks/interfaces/IWalletProxy.sol';
import 'contracts/modules/commons/ModuleHooks.sol';
import 'contracts/Factory.sol';

import 'foundry_test/base/AdvTest.sol';

contract WalletProxyHookTest is AdvTest {
  ModuleHooks private template;
  ModuleHooks private walletMod;
  WalletProxyHook private wallet;

  function setUp() external {
    Factory factory = new Factory();
    template = new ModuleHooks();
    walletMod = ModuleHooks(payable(factory.deploy(address(template), bytes32(0))));
    WalletProxyHook hook = new WalletProxyHook();

    // Add hook
    vm.prank(address(walletMod));
    walletMod.addHook(IWalletProxy.PROXY_getImplementation.selector, address(hook));

    wallet = WalletProxyHook(address(walletMod));
    vm.label(address(wallet), 'wallet');
  }

  //
  // Get Implementation
  //

  function test_PROXY_getImplementation() external {
    assertEq(wallet.PROXY_getImplementation(), address(template));
  }
}


================================================
FILE: foundry_test/modules/commons/Implementation.t.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "contracts/modules/commons/Implementation.sol";
import "contracts/Factory.sol";

import "foundry_test/base/AdvTest.sol";


contract ImplementationImp is Implementation {
  function setImplementation(address _imp) external {
    _setImplementation(_imp);
  }

  function getImplementation() external view returns (address) {
    return _getImplementation();
  }

  function stub() external virtual pure returns (uint256) {
    return 1;
  }
}

contract NextImplementation is ImplementationImp {
  function stub() external override pure returns (uint256) {
    return 2;
  }
}

contract ImplementationTest is AdvTest {
  function test_setImplementation(address _imp, address _next) external {
    boundNoContract(boundNoSys(_imp));

    vm.etch(_imp, address(new ImplementationImp()).code);

    assertEq(ImplementationImp(_imp).getImplementation(), address(0));

    ImplementationImp(_imp).setImplementation(_next);

    assertEq(ImplementationImp(_imp).getImplementation(), _next);
    assertEq(vm.load(_imp, addrToBytes32(_imp)), addrToBytes32(_next));
  }

  function test_setImplementation_matchWallet(bytes32 _salt, address _imp, address _imp2) external {
    Factory factory = new Factory();

    ImplementationImp imp = new ImplementationImp();
    ImplementationImp imp2 = new NextImplementation();

    boundNoContract(boundDiff(boundNoSys(_imp), address(factory)));
    boundNoContract(boundDiff(boundNoSys(_imp2), address(factory)));

    vm.etch(_imp, address(imp).code);
    address wallet = factory.deploy(_imp, _salt);

    assertEq(ImplementationImp(wallet).getImplementation(), _imp);
    assertEq(ImplementationImp(wallet).stub(), 1);

    vm.etch(_imp2, address(imp2).code);

    ImplementationImp(wallet).setImplementation(_imp2);

    assertEq(ImplementationImp(wallet).getImplementation(), _imp2);
    assertEq(vm.load(wallet, addrToBytes32(wallet)), addrToBytes32(_imp2));
    assertEq(ImplementationImp(wallet).stub(), 2);
  }
}


================================================
FILE: foundry_test/modules/commons/ModuleCalls.t.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "contracts/modules/commons/ModuleCalls.sol";
import "contracts/Factory.sol";

import "foundry_test/base/AdvTest.sol";


contract ImmutableBytes {
  bytes public b;

  constructor (bytes memory _b) {
    b = _b;
  }

  fallback() external payable {}
  receive() external payable {}
}

contract WillRevert {
  ImmutableBytes immutable private ib;

  constructor (bytes memory _err) {
    ib = new ImmutableBytes(_err);
  }

  fallback() external payable {
    _revert();
  }

  receive() external payable {
    _revert();
  }

  function _revert() internal view {
    bytes memory e = ib.b();
    assembly {
      revert(add(e, 32), mload(e))
    }
  }
}

contract WillDelegateTo {
  address immutable private expectSelf;
  bytes32 immutable private expectData;
  address immutable private delegate;

  constructor (address _expectSelf, bytes memory _expectData) {
    expectSelf = _expectSelf;
    expectData = keccak256(_expectData);
    delegate = address(this);
  }

  fallback() external payable {
    _check();
  }

  receive() external payable {
    _check();
  }

  function _check() internal {
    bytes32 dataHash = keccak256(msg.data);
    require(dataHash == expectData && address(this) == expectSelf);

    bytes32 key = keccak256(abi.encode(delegate));
    assembly { sstore(key, add(sload(key), 1)) }
  }
}

contract ModuleCallsImp is ModuleCalls {
  function validateNonce(uint256 _rawNonce) external {
    _validateNonce(_rawNonce);
  }

  function writeNonce(uint256 _space, uint256 _nonce) external {
    _writeNonce(_space, _nonce);
  }

  // Module Auth imp
  mapping(bytes32 => mapping(bytes => bytes32)) public sigToSubdigest;
  mapping(bytes32 => mapping(bytes => bool)) public sigToIsValid;

  function _signatureValidation(
    bytes32 _digest,
    bytes calldata _signature
  ) internal override view returns (
    bool isValid,
    bytes32 subdigest
  ) {
    subdigest = sigToSubdigest[_digest][_signature];
    isValid = sigToIsValid[_digest][_signature];
  }

  function mockSignature(
    bytes32 _digest,
    bytes calldata _signature,
    bytes32 _subdigest,
    bool _isValid
  ) external  {
    sigToSubdigest[_digest][_signature] = _subdigest;
    sigToIsValid[_digest][_signature] = _isValid;
  }

  function signatureRecovery(bytes32, bytes calldata) public override view returns (
    uint256, uint256, bytes32, bytes32, uint256
  ) {
  }

  function _isValidImage(bytes32) internal override view returns (bool) {
  }

  function updateImageHash(bytes32) external override {
  }

  function _updateImageHash(bytes32) internal override {
  }
}

contract ModuleCallsTest is AdvTest {
  ModuleCallsImp private template;
  ModuleCallsImp private imp;
  Factory private factory;

  function setUp() external {
    template = new ModuleCallsImp();
    factory = new Factory();
    imp = ModuleCallsImp(factory.deploy(address(template), bytes32(0)));
  }

  struct ToValAndData {
    address target;
    uint256 value;
    bytes data;
  }

  event TxExecuted(bytes32 _tx) anonymous;
  event NonceChange(uint256 _space, uint256 _newNonce);
  event TxFailed(bytes32 _tx, bytes _reason);
  event GapNonceChange(uint256 _space, uint256 _oldNonce, uint256 _newNonce);
  event NoNonceUsed();

  function test_execute(ToValAndData[] memory _rtxs, bytes memory _sig, bytes32 _subdigest) external {
    uint256 size = mayBoundArr(_rtxs.length);
    IModuleCalls.Transaction[] memory txs = new IModuleCalls.Transaction[](size);
    uint256 total;

    for (uint256 i = 0; i < size; i++) {
      txs[i].data = _rtxs[i].data;
      txs[i].target = boundNoBalance(boundNoContract(boundDiff(boundNoSys(_rtxs[i].target), address(template), address(imp), address(factory))));
      txs[i].value = bound(_rtxs[i].value, 0, type(uint256).max - total);

      total += txs[i].value;
    }

    vm.deal(address(imp), total);
    bytes32 digest = keccak256(abi.encode(0, txs));
    imp.mockSignature(digest, _sig, _subdigest, false);

    vm.expectRevert(abi.encodeWithSignature('InvalidSignature(bytes32,bytes)', _subdigest, _sig));
    imp.execute(txs, 0, _sig);

    vm.expectRevert(abi.encodeWithSignature('BadNonce(uint256,uint256,uint256)', 0, 1, 0));
    imp.execute(txs, 1, _sig);

    imp.mockSignature(digest, _sig, _subdigest, true);

    vm.expectEmit(true, true, true, true, address(imp));
    emit NonceChange(0, 1);

    for (uint256 i = 0; i < size; i++) {
      vm.expectCall(txs[i].target, txs[i].data);
    }

    imp.execute(txs, 0, _sig);

    assertEq(imp.nonce(), 1);

    for (uint256 i = 0; i < size; i++) {
      assertTrue(txs[i].target.balance >= txs[i].value);
    }
  }

  function test_execute_reverts(
    ToValAndData[] memory _rtxs,
    uint256 _reverti,
    bool _revertsOnErr,
    bool _delegateCall,
    bytes memory _err,
    bytes memory _sig,
    bytes32 _subdigest
  ) external {
    uint256 size = mayBoundArr(_rtxs.length);
    vm.assume(size != 0);

    IModuleCalls.Transaction[] memory txs = new IModuleCalls.Transaction[](size);
    uint256 total;

    _reverti = bound(_reverti, 0, size - 1);

    address willRevert = address(new WillRevert(_err));

    for (uint256 i = 0; i < size; i++) {
      if (_reverti == i) {
        txs[i].target = willRevert;
        txs[i].revertOnError = _revertsOnErr;
        txs[i].delegateCall = _delegateCall;
      } else {
        txs[i].target = boundNoBalance(boundNoContract(boundDiff(boundNoSys(_rtxs[i].target), address(template), address(imp), address(factory))));
      }

      txs[i].data = _rtxs[i].data;
      txs[i].value = bound(_rtxs[i].value, 0, type(uint256).max - total);

      total += txs[i].value;
    }

    vm.deal(address(imp), total);

    bytes32 digest = keccak256(abi.encode(0, txs));
    imp.mockSignature(digest, _sig, _subdigest, true);


    if (_revertsOnErr) {
      vm.expectRevert(_err);
    }

    imp.execute(txs, 0, _sig);

    for (uint256 i = 0; i < size; i++) {
      if (_revertsOnErr || txs[i].target == willRevert) {
        assertEq(txs[i].target.balance, 0);
      } else {
        assertTrue(txs[i].target.balance >= txs[i].value);
      }
    }
  }

  function test_execute_delegateCall(
    ToValAndData[] memory _rtxs,
    bytes memory _sig,
    bytes32 _subdigest
  ) external {
    uint256 size = mayBoundArr(_rtxs.length);
    IModuleCalls.Transaction[] memory txs = new IModuleCalls.Transaction[](size);

    for (uint256 i = 0; i < size; i++) {
      txs[i].data = _rtxs[i].data;
      txs[i].target = address(new WillDelegateTo(address(imp), _rtxs[i].data));
      txs[i].value = _rtxs[i].value;
      txs[i].delegateCall = true;
    }

    bytes32 digest = keccak256(abi.encode(0, txs));
    imp.mockSignature(digest, _sig, _subdigest, true);

    imp.execute(txs, 0, _sig);
    assertEq(imp.nonce(), 1);

    for (uint256 i = 0; i < size; i++) {
      bytes32 key = keccak256(abi.encode(txs[i].target));
      assertTrue(uint256(vm.load(address(imp), key)) != 0);
    }
  }

  function test_selfExecute(ToValAndData[] memory _rtxs) external {
    uint256 size = mayBoundArr(_rtxs.length);
    IModuleCalls.Transaction[] memory txs = new IModuleCalls.Transaction[](size);
    uint256 total;

    for (uint256 i = 0; i < size; i++) {
      txs[i].data = _rtxs[i].data;
      txs[i].target = boundNoBalance(boundNoContract(boundDiff(boundNoSys(_rtxs[i].target), address(template), address(imp), address(factory))));
      txs[i].value = bound(_rtxs[i].value, 0, type(uint256).max - total);

      total += txs[i].value;
    }

    vm.deal(address(imp), total);

    for (uint256 i = 0; i < size; i++) {
      vm.expectCall(txs[i].target, txs[i].data);
    }

    vm.prank(address(imp));
    imp.selfExecute(txs);

    for (uint256 i = 0; i < size; i++) {
      assertTrue(txs[i].target.balance >= txs[i].value);
    }
  }

  function test_fail_selfExecute_NotSelf(ToValAndData[] memory _rtxs, address _notself) external {
    _notself = boundDiff(_notself, address(imp));

    uint256 size = mayBoundArr(_rtxs.length);
    IModuleCalls.Transaction[] memory txs = new IModuleCalls.Transaction[](size);

    for (uint256 i = 0; i < size; i++) {
      txs[i].data = _rtxs[i].data;
      txs[i].target = _rtxs[i].target;
      txs[i].value = _rtxs[i].value;
    }

    vm.prank(_notself);
    vm.expectRevert(abi.encodeWithSignature('OnlySelfAuth(address,address)', _notself, address(imp)));
    imp.selfExecute(txs);
  }

  function test_validateNonce_Normal(
    uint160 _space,
    uint88 _nonce
  ) external {
    uint256 encoded = uint256(
      abi.decode(
        abi.encodePacked(
          _space,
          uint8(0),
          _nonce
        ),
        (bytes32))
    );

    imp.writeNonce(_space, _nonce);

    vm.expectEmit(true, true, true, true, address(imp));
    emit NonceChange(_space, uint256(_nonce) + 1);
    imp.validateNonce(encoded);

    assertEq(imp.readNonce(_space), uint256(_nonce) + 1);
    assertEq(imp.nonce(), _space == 0 ? uint256(_nonce) + 1 : 0);
  }

 function test_fail_validateNonce_Normal_Bad(
    uint160 _space,
    uint88 _nonce,
    uint88 _badprev
  ) external {
    _badprev = uint88(boundDiff(_badprev, _nonce));

    uint256 encoded = uint256(
      abi.decode(
        abi.encodePacked(
          _space,
          uint8(0),
          _nonce
        ),
        (bytes32))
    );

    imp.writeNonce(_space, _badprev);

    vm.expectRevert(abi.encodeWithSignature('BadNonce(uint256,uint256,uint256)', _space, _nonce, _badprev));
    imp.validateNonce(encoded);
  }

  function test_fail_noDelegatecall(ToValAndData[] memory _rtxs, bytes memory _sig, uint256 _nonce) external {
    uint256 size = mayBoundArr(_rtxs.length);
    IModuleCalls.Transaction[] memory txs = new IModuleCalls.Transaction[](size);
    uint256 total;

    for (uint256 i = 0; i < size; i++) {
      txs[i].data = _rtxs[i].data;
      txs[i].target = boundNoSys(_rtxs[i].target);
      txs[i].value = bound(_rtxs[i].value, 0, type(uint256).max - total);

      total += txs[i].value;
    }

    vm.deal(address(imp), total);
    vm.expectRevert(abi.encodeWithSignature('OnlyDelegatecall()'));
    template.execute(txs, _nonce, _sig);
  }
}


================================================
FILE: foundry_test/modules/commons/ModuleERC5719.t.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "contracts/modules/commons/ModuleERC5719.sol";

import "foundry_test/base/AdvTest.sol";

contract ModuleERC5719Test is AdvTest {
  ModuleERC5719 private module;

  function setUp() public {
    module = new ModuleERC5719();
  }

  function test_getAlternativeSignature() external {
    // 0xba5a3cbb592813d90eae65a3aac33e9b6dfc7be50623aa25e151fe3da06c8443
    // ==
    // ipfs://bafybeif2li6lwwjicpmq5ltfuovmgpu3nx6hxzigeovclykr7y62a3eeim

    // 0xb6f77d000c8791676d96aedac165dd1bb2da4a5baf78198b9f391fc76b893f46
    // ==
    // ipfs://bafybeifw656qadehsftw3fvo3lawlxi3wlneuw5ppamyxhzzd7dwxcj7iy

    vm.startPrank(address(module));

    bytes32 root = 0xba5a3cbb592813d90eae65a3aac33e9b6dfc7be50623aa25e151fe3da06c8443;
    module.updateIPFSRoot(root);

    assertEq(
      module.getAlternativeSignature(0x64f16a2f2c80ab7f3b0e0edc67c0bf1399402dc389cfb4271ba58abe3f61ea16),
      'ipfs://bafybeif2li6lwwjicpmq5ltfuovmgpu3nx6hxzigeovclykr7y62a3eeim/ERC5719/0x64f16a2f2c80ab7f3b0e0edc67c0bf1399402dc389cfb4271ba58abe3f61ea16'
    );

    root = 0xb6f77d000c8791676d96aedac165dd1bb2da4a5baf78198b9f391fc76b893f46;
    module.updateIPFSRoot(root);

    assertEq(
      module.getAlternativeSignature(0x11b858b3b52eb84e900639ebb082aeacb10bd9d239f58ae3f7092885cc3593b6),
      'ipfs://bafybeifw656qadehsftw3fvo3lawlxi3wlneuw5ppamyxhzzd7dwxcj7iy/ERC5719/0x11b858b3b52eb84e900639ebb082aeacb10bd9d239f58ae3f7092885cc3593b6'
    );
  }
}


================================================
FILE: foundry_test/modules/commons/ModuleExtraAuth.t.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "contracts/modules/commons/ModuleExtraAuth.sol";

import "foundry_test/base/AdvTest.sol";


contract ExtStore {
  mapping(bytes32 => bool) private imageHashToIsValid;

  function setValidImageHash(bytes32 _imageHash, bool _isValid) external {
    imageHashToIsValid[_imageHash] = _isValid;
  }

  function isValidImage(bytes32 _imageHash) external view returns (bool) {
    return imageHashToIsValid[_imageHash];
  }
}

abstract contract ModuleAuthImp is IModuleAuth {
  ExtStore private immutable EXT_STORE;

  constructor() {
    EXT_STORE = new ExtStore();
  }

  function setValidImageHash(bytes32 _imageHash, bool _isValid) external {
    EXT_STORE.setValidImageHash(_imageHash, _isValid);
  }

  function _isValidImage(bytes32 _imageHash) internal override virtual view returns (bool) {
    return EXT_STORE.isValidImage(_imageHash);
  }
}

contract ModuleExtraAuthImp2 is ModuleAuthImp, ModuleExtraAuth {
  function _isValidImage(bytes32 _imageHash) internal override(
    ModuleAuthImp,
    ModuleExtraAuth
  ) view returns (bool) {
    return super._isValidImage(_imageHash);
  }

  function isValidImage(bytes32 _imageHash) external view returns (bool) {
    return _isValidImage(_imageHash);
  }

  function _updateImageHash(bytes32) internal override virtual {
    revert('not implemented');
  }
}

contract ModuleExtraAuthTest is AdvTest {
  ModuleExtraAuthImp2 private imp;

  function setUp() public {
    imp = new ModuleExtraAuthImp2();
  }

  event SetExtraImageHash(bytes32 indexed _imageHash, uint256 _expiration);

  function test_shouldAcceptExtraImageHashes(
    bytes32 _imageHashb,
    bytes32 _imageHash1,
    bytes32 _imageHash2,
    uint256 _expiration1,
    uint256 _expiration2
  ) external {
    _expiration1 = bound(_expiration1, block.timestamp + 1, type(uint256).max);
    _expiration2 = bound(_expiration2, block.timestamp + 1, type(uint256).max);

    assertFalse(imp.isValidImage(_imageHashb));
    assertFalse(imp.isValidImage(_imageHash1));
    assertFalse(imp.isValidImage(_imageHash2));

    imp.setValidImageHash(_imageHashb, true);
    assertTrue(imp.isValidImage(_imageHashb));
    assertEq(imp.isValidImage(_imageHash1), _imageHash1 == _imageHashb);
    assertEq(imp.isValidImage(_imageHash2), _imageHash2 == _imageHashb);

    vm.prank(address(imp));
    vm.expectEmit(true, true, true, true, address(imp));
    emit SetExtraImageHash(_imageHash1, _expiration1);
    imp.setExtraImageHash(_imageHash1, _expiration1);

    assertTrue(imp.isValidImage(_imageHash1));
    assertEq(imp.isValidImage(_imageHash2), _imageHash1 == _imageHash2 || _imageHashb == _imageHash2);
    assertTrue(imp.isValidImage(_imageHashb));

    vm.prank(address(imp));
    vm.expectEmit(true, true, true, true, address(imp));
    emit SetExtraImageHash(_imageHash2, _expiration2);
    imp.setExtraImageHash(_imageHash2, _expiration2);

    assertTrue(imp.isValidImage(_imageHashb));
    assertTrue(imp.isValidImage(_imageHash1));
    assertTrue(imp.isValidImage(_imageHash2));
  }

  function test_shouldRejectExpiredImageHash(
    bytes32 _imageHashb,
    bytes32 _imageHash1,
    bytes32 _imageHash2,
    uint256 _expiration1,
    uint256 _expiration2
  ) external {
    _expiration1 = bound(_expiration1, block.timestamp + 1, type(uint256).max);
    _expiration2 = bound(_expiration2, 0,  block.timestamp);

    imp.setValidImageHash(_imageHashb, true);

    vm.prank(address(imp));
    vm.expectEmit(true, true, true, true, address(imp));
    emit SetExtraImageHash(_imageHash1, _expiration1);
    imp.setExtraImageHash(_imageHash1, _expiration1);

    vm.prank(address(imp));
    vm.expectEmit(true, true, true, true, address(imp));
    emit SetExtraImageHash(_imageHash2, _expiration2);
    imp.setExtraImageHash(_imageHash2, _expiration2);

    assertTrue(imp.isValidImage(_imageHashb));
    assertEq(imp.isValidImage(_imageHash1), _imageHash1 != _imageHash2 || _imageHash1 == _imageHashb);
    assertEq(imp.isValidImage(_imageHash2), _imageHash2 == _imageHashb);
  }

  struct SetIh {
    bytes32 imageHash;
    uint256 expiration;
  }

  mapping(bytes32 => bool) private wasCleared;

  function test_shouldClearExtraImageHashes(
    bytes32 _base,
    SetIh[] calldata _set,
    bytes32[] calldata _clear
  ) external {
    uint256 sizeSet = mayBoundArr(_set.length);
    uint256 sizeClear = mayBoundArr(_clear.length);

    imp.setValidImageHash(_base, true);

    vm.startPrank(address(imp));
    for (uint256 i = 0; i < sizeSet; i++) {
      uint256 expiration = bound(_set[i].expiration, block.timestamp + 1, type(uint256).max);
      imp.setExtraImageHash(_set[i].imageHash, expiration);
    }

    bytes32[] memory toClear = new bytes32[](sizeClear);
    for (uint256 i = 0; i < sizeClear; i++) {
      toClear[i] = _clear[i];
    }

    imp.clearExtraImageHashes(toClear);

    for (uint256 i = 0; i < sizeClear; i++) {
      assertEq(imp.isValidImage(_clear[i]), _clear[i] == _base);
      wasCleared[_clear[i]] = true;
    }

    for (uint256 i = 0; i < sizeSet; i++) {
      assertEq(
        imp.isValidImage(_set[i].imageHash),
        _set[i].imageHash == _base || !wasCleared[_set[i].imageHash]
      );
    }
  }

  function test_fail_setExtraImageHash_notSelf(
    address _caller,
    bytes32 _imageHash,
    uint256 _expiration
  ) external {
    boundDiff(_caller, address(imp));
    vm.expectRevert(abi.encodeWithSignature('OnlySelfAuth(address,address)', _caller, address(imp)));
    vm.prank(_caller);
    imp.setExtraImageHash(_imageHash, _expiration);
  }

  function test_fail_clearExtraImageHash_notSelf(
    address _caller,
    bytes32[] calldata _clear
  ) external {
    boundDiff(_caller, address(imp));
    vm.expectRevert(abi.encodeWithSignature('OnlySelfAuth(address,address)', _caller, address(imp)));
    vm.prank(_caller);
    imp.clearExtraImageHashes(_clear);
  }
}


================================================
FILE: foundry_test/modules/commons/ModuleIPFS.t.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "contracts/modules/commons/ModuleIPFS.sol";

import "foundry_test/base/AdvTest.sol";

contract ModuleIPFSTest is AdvTest {
  ModuleIPFS private module;

  function setUp() public {
    module = new ModuleIPFS();
  }

  function test_exposeRoot() external {
    // 0xba5a3cbb592813d90eae65a3aac33e9b6dfc7be50623aa25e151fe3da06c8443
    // ==
    // ipfs://bafybeif2li6lwwjicpmq5ltfuovmgpu3nx6hxzigeovclykr7y62a3eeim

    // 0xb6f77d000c8791676d96aedac165dd1bb2da4a5baf78198b9f391fc76b893f46
    // ==
    // ipfs://bafybeifw656qadehsftw3fvo3lawlxi3wlneuw5ppamyxhzzd7dwxcj7iy

    vm.startPrank(address(module));

    bytes32 root = 0xba5a3cbb592813d90eae65a3aac33e9b6dfc7be50623aa25e151fe3da06c8443;
    module.updateIPFSRoot(root);

    assertEq(module.ipfsRootBytes32(), root);
    assertEq(
      module.ipfsRoot(),
      'ipfs://bafybeif2li6lwwjicpmq5ltfuovmgpu3nx6hxzigeovclykr7y62a3eeim'
    );

    root = 0xb6f77d000c8791676d96aedac165dd1bb2da4a5baf78198b9f391fc76b893f46;
    module.updateIPFSRoot(root);

    assertEq(module.ipfsRootBytes32(), root);
    assertEq(
      module.ipfsRoot(),
      'ipfs://bafybeifw656qadehsftw3fvo3lawlxi3wlneuw5ppamyxhzzd7dwxcj7iy'
    );
  }

  function test_fail_updateIPFSRoot_notSelf(address _notSelf) external {
    boundDiff(_notSelf, address(module));

    vm.prank(address(_notSelf));
    vm.expectRevert(abi.encodeWithSignature('OnlySelfAuth(address,address)', _notSelf, address(module)));
    module.updateIPFSRoot(0x0);
  }
}


================================================
FILE: foundry_test/modules/commons/ModuleStorage.t.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "contracts/modules/commons/ModuleStorage.sol";

import "foundry_test/base/AdvTest.sol";


contract ModuleStorageImp {
  function writeBytes32(bytes32 _key, bytes32 _val) external {
    ModuleStorage.writeBytes32(_key, _val);
  }

  function readBytes32(bytes32 _key) external view returns (bytes32) {
    return ModuleStorage.readBytes32(_key);
  }

  function writeBytes32Map(bytes32 _key, bytes32 _subKey, bytes32 _val) external {
    ModuleStorage.writeBytes32Map(_key, _subKey, _val);
  }

  function readBytes32Map(bytes32 _key, bytes32 _subKey) external view returns (bytes32) {
    return ModuleStorage.readBytes32Map(_key, _subKey);
  }
}


contract ModuleStorageTest is AdvTest {
  ModuleStorageImp private imp;

  function setUp() external {
    imp = new ModuleStorageImp();
  }

  function test_writeBytes32(
    bytes32 _key1,
    bytes32 _key2,
    bytes32 _val1,
    bytes32 _val2
  ) external {
    assertEq(imp.readBytes32(_key1), bytes32(0));
    assertEq(imp.readBytes32(_key2), bytes32(0));

    bool equal = _key1 == _key2;

    imp.writeBytes32(_key1, _val1);

    bytes32 res1 = imp.readBytes32(_key1);
    assertEq(res1, _val1);
    assertEq(vm.load(address(imp), _key1), res1);

    imp.writeBytes32(_key2, _val2);

    bytes32 res2 = imp.readBytes32(_key2);
    res1 = imp.readBytes32(_key1);

    assertEq(res1, equal ? _val2 : _val1);
    assertEq(res2, _val2);
    assertEq(vm.load(address(imp), _key1), res1);
    assertEq(vm.load(address(imp), _key2), res2);
  }

  function test_writeBytes32Map(
    bytes32 _key1,
    bytes32 _subkey1,
    bytes32 _val1,
    bytes32 _key2,
    bytes32 _subkey2,
    bytes32 _val2
  ) external {
    bool equal = _key1 == _key2 && _subkey1 == _subkey2;
    bytes32 slot1 = keccak256(abi.encode(_key1, _subkey1));
    bytes32 slot2 = keccak256(abi.encode(_key2, _subkey2));
    assertEq(slot1 == slot2, equal);

    imp.writeBytes32Map(_key1, _subkey1, _val1);
    bytes32 res1 = imp.readBytes32Map(_key1, _subkey1);
    assertEq(res1, _val1);
    assertEq(vm.load(address(imp), slot1), res1);

    imp.writeBytes32Map(_key2, _subkey2, _val2);

    bytes32 res2 = imp.readBytes32Map(_key2, _subkey2);
    res1 = imp.readBytes32Map(_key1, _subkey1);

    assertEq(res1, equal ? _val2 : _val1);
    assertEq(res2, _val2);
    assertEq(vm.load(address(imp), slot1), res1);
    assertEq(vm.load(address(imp), slot2), res2);
  }
}


================================================
FILE: foundry_test/modules/commons/submodules/auth/SequenceBaseSig.t.sol
================================================
// SPDX-License-Identifier: Apache-2.0
pragma solidity 0.8.18;

import "contracts/modules/commons/submodules/auth/SequenceBaseSig.sol";

import "foundry_test/base/AdvTest.sol";


contract SequenceBaseSigImp {
  function subdigest(bytes32 _digest) external view returns (bytes32) {
    return SequenceBaseSig.subdigest(_digest);
  }

  function leafForAddressAndWeight(address _addr, uint96 _weight) external pure returns (bytes32) {
    return SequenceBaseSig._leafForAddressAndWeight(_addr, _weight);
  }

  function recoverBranch(bytes32 _digest, bytes calldata _signature) external view returns (uint256 weight, bytes32 root) {
    return SequenceBaseSig.recoverBranch(_digest, _signature);
  }

  function recover(bytes32 _subdigest, bytes calldata _signature) external view returns (uint256 threshold, uint256 weight, bytes32 imageHash, uint256 checkpoint) {
    return SequenceBaseSig.recover(_subdigest, _signature);
  }
}

contract SequenceBaseSigTest is AdvTest {
  SequenceBaseSigImp private lib;

  uint8 private constant FLAG_SIGNATURE = 0;
  uint8 private constant FLAG_ADDRESS = 1;
  uint8 private constant FLAG_DYNAMIC_SIGNATURE = 2;
  uint8 private constant FLAG_NODE = 3;
  uint8 private constant FLAG_BRANCH = 4;
  uint8 private constant FLAG_SUBDIGEST = 5;
  uint8 private constant FLAG_NESTED = 6;

  function setUp() public {
    lib = new SequenceBaseSigImp();
  }

  function test_subdigest(bytes32 _digest, uint256 _chainId) external {
    _chainId = bound(_chainId, 0, type(uint64).max);

    bytes32 expected = keccak256(
      abi.encodePacked(
        "\x19\x01",
        _chainId,
        address(lib),
        _digest
      )
    );

    vm.chainId(_chainId);
    bytes32 actual = lib.subdigest(_digest);
    assertEq(actual, expected);
  }

  function test_subdigest_Fuzz_ChainId(bytes32 _digest, uint256 _chainId1, uint256 _chainId2) external {
    _chainId1 = bound(_chainId1, 0, type(uint64).max);
    _chainId2 = bound(_chainId2, 0, type(uint64).max);

    vm.chainId(_chainId1);
    bytes32 subdigest1 = lib.subdigest(_digest);

    vm.chainId(_chainId2);
    bytes32 subdigest2 = lib.subdigest(_digest);

    assertTrue(subdigest1 != subdigest2 || _chainId1 == _chainId2);
  }

  function test_subdigest_Fuzz_Digest(bytes32 _digest1, bytes32 _digest2) external {
    bytes32 subdigest1 = lib.subdigest(_digest1);
    bytes32 subdigest2 = lib.subdigest(_digest2);

    assertTrue(subdigest1 != subdigest2 || _digest1 == _digest2);
  }

  function test_subdigest_Fuzz_Address(bytes32 _digest, address _addr1, address _addr2) external {
    boundNoSys(_addr1);
    boundNoSys(_addr2);

    vm.etch(_addr1, address(lib).code);
    vm.etch(_addr2, address(lib).code);

    bytes32 subdigest1 = SequenceBaseSigImp(_addr1).subdigest(_digest);
    bytes32 subdigest2 = SequenceBaseSigImp(_addr2).subdigest(_digest);

    assertTrue(subdigest1 != subdigest2 || _addr1 == _addr2);
  }

  function test_leafForAddressAndWeight(address _addr, uint96 _weight) external {
    bytes32 expected = abi.decode(abi.encodePacked(_weight, _addr), (bytes32));
    bytes32 actual = lib.leafForAddressAndWeight(_addr, _weight);
    assertEq(expected, actual);
  }

  function test_leafForAddressAndWeight_fuzz(address _addr1, uint96 _weight1, address _addr2, uint96 _weight2) external {
    bytes32 encoded1 = lib.leafForAddressAndWeight(_addr1, _weight1);
    bytes32 encoded2 = lib.leafForAddressAndWeight(_addr2, _weight2);
    assertEq(encoded1 == encoded2, _addr1 == _addr2 && _weight1 == _weight2);
  }

  function test_leafForHardcodedSubdigest_fuzz(bytes32 _subdigest1, bytes32 _subdigest2) external {
    bytes32 encoded1 = SequenceBaseSig._leafForHardcodedSubdigest(_subdigest1);
    bytes32 encoded2 = SequenceBaseSig._leafForHardcodedSubdigest(_subdigest2);
    assertEq(encoded1 == encoded2, _subdigest1 == _subdigest2);
  }

  function test_leafForHardcodedSubdigest_fuzz_addr(address _addr, uint96 _weight, bytes32 _subdigest) external {
    bytes32 encoded1 = SequenceBaseSig._leafForHardcodedSubdigest(_subdigest);
    bytes32 encoded2 = SequenceBaseSig._leafForAddressAndWeight(_addr, _weight);
    assertTrue(encoded1 != encoded2);
  }

  function test_leafForNested_fuzz(
    bytes32 _node1,
    uint256 _threshold1,
    uint256 _weight1,
    bytes32 _node2,
    uint256 _threshold2,
    uint256 _weight2
  ) external {
    bytes32 encoded1 = SequenceBaseSig._leafForNested(_node1, _threshold1, _weight1);
    bytes32 encoded2 = SequenceBaseSig._leafForNested(_node2, _threshold2, _weight2);
    assertEq(encoded1 == encoded2, _node1 == _node2 && _threshold1 == _threshold2 && _weight1 == _weight2);
  }

  function test_leafForNested_fuzz_addr(
    address _addr,
    uint96 _weight,
    bytes32 _node,
    uint256 _threshold,
    uint256 _nodeWeight
  ) external {
    bytes32 encoded1 = SequenceBaseSig._leafForNested(_node, _threshold, _nodeWeight);
    bytes32 encoded2 = SequenceBaseSig._leafForAddressAndWeight(_addr, _weight);
    assertTrue(encoded1 != encoded2);
  }

  function test_leafForNested_fuzz_subdigest(
    bytes32 _subdigest,
    bytes32 _node,
    uint256 _threshold,
    uint256 _weight
  ) external {
    bytes32 encoded1 = SequenceBaseSig._leafForNested(_node, _threshold, _weight);
    bytes32 encoded2 = SequenceBaseSig._leafForHardcodedSubdigest(_subdigest);
    assertTrue(encoded1 != encoded2);
  }

  function test_recoverBranch_Addresses(bytes32 _subdigest, bytes32 _seed, address[] calldata _addresses) external {
    bytes memory signature;
    bytes32 root;

    uint256 size = mayBoundArr(_addresses.length);
    for (uint256 i = 0; i < size; i++) {
      uint8 randomWeight = uint8(bound(uint256(keccak256(abi.encode(_addresses[i], i, _seed))), 0, type(uint8).max));

      signature = abi.encodePacked(signature, FLAG_ADDRESS, randomWeight, _addresses[i]);
      bytes32 node = lib.leafForAddressAndWeight(_addresses[i], randomWeight);
      root = root != bytes32(0) ? keccak256(abi.encodePacked(root, node)) : node;
    }

    (uint256 recoveredWeight, bytes32 recoveredRoot) = lib.recoverBranch(_subdigest, signature);
    assertEq(recoveredRoot, root);
    assertEq(recoveredWeight, 0);
  }

  function test_recoverBranch_Nodes(bytes32 _subdigest, bytes32[] calldata _nodes) external {
    bytes memory signature;
    bytes32 root;

    uint256 size = mayBoundArr(_nodes.length);
    for (uint256 i = 0; i < size; i++) {
      signature = abi.encodePacked(signature, FLAG_NODE, _nodes[i]);
      root = root != bytes32(0) ? keccak256(abi.encodePacked(root, _nodes[i])) : _nodes[i];
    }

    (uint256 recoveredWeight, bytes32 recoveredRoot) = lib.recoverBranch(_subdigest, signature);
    assertEq(recoveredRoot, root);
    assertEq(recoveredWeight, 0);
  }

  function test_recoverBranch_Signatures(bytes32 _subdigest, bytes32 _seed, uint256[] memory _pks) external {
    bytes memory signature;
    bytes32 root;
    uint256 total;

    uint256 size = mayBoundArr(_pks.length);
    for (uint256 i = 0; i < size; i++) {
      _pks[i] = boundPk(_pks[i]);

      uint8 randomWeight = uint8(bound(uint256(keccak256(abi.encode(_pks[i], i, _seed))), 0, type(uint8).max));
      address addr = vm.addr(_pks[i]);

      // Determine if the pk will sign, dynamic sign or just sit as addr
      uint256 op = bound(uint256(keccak256(abi.encode(_pks[i], i, _seed, 2))), 0, 2);

      if (op == 0) {
        signature = abi.encodePacked(signature, FLAG_ADDRESS, randomWeight, addr);
      } else {
        bytes memory sigpart = signAndPack(_pks[i], _subdigest, 1);

        total += randomWeight;

        if (op == 1) {
          signature = abi.encodePacked(signature, FLAG_SIGNATURE, randomWeight, sigpart);
        } else {
          signature = abi.encodePacked(signature, FLAG_DYNAMIC_SIGNATURE, randomWeight, addr, uint24(sigpart.length), sigpart);
        }
      }

      bytes32 node = lib.leafForAddressAndWeight(addr, randomWeight);
      root = root != bytes32(0) ? keccak256(abi.encodePacked(root, node)) : node;
    }

    (uint256 recoveredWeight, bytes32 recoveredRoot) = lib.recoverBranch(_subdigest, signature);
    assertEq(recoveredRoot, root);
    assertEq(recoveredWeight, total);
  }

  function test_recoverBranch_Branches(bytes32 _subdigest, bytes32 _seed, uint256[] memory _pks) external {
    bytes memory signature;
    bytes32 root;
    uint256 total;

    // NOTICE: too much branching will lead to stack overflow
    uint256 size = bound(_pks.length, 0, 32);

    for (uint256 i = 0; i < size; i++) {
      if (i != 0) {
        signature = abi.encodePacked(FLAG_BRANCH, uint24(signature.length), signature);
      }

      _pks[i] = boundPk(_pks[i]);

      uint8 randomWeight = uint8(bound(uint256(keccak256(abi.encode(_pks[i], i, _seed))), 0, type(uint8).max));
      address addr = vm.addr(_pks[i]);

      // Determine if the pk will sign, dynamic sign or just sit as addr
      uint256 op = bound(uint256(keccak256(abi.encode(_pks[i], i, _seed, 2))), 0, 2);

      if (op == 0) {
        signature = abi.encodePacked(FLAG_ADDRESS, randomWeight, addr, signature);
      } else {
        bytes memory sigpart = signAndPack(_pks[i], _subdigest, 1);

        total += randomWeight;

        if (op == 1) {
          signature = abi.encodePacked(FLAG_SIGNATURE, randomWeight, sigpart, signature);
        } e
Download .txt
gitextract_1y31azvd/

├── .eslintignore
├── .eslintrc.js
├── .gitattributes
├── .github/
│   ├── actions/
│   │   └── install-dependencies/
│   │       └── action.yml
│   └── workflows/
│       └── ci.yml
├── .gitignore
├── .gitmodules
├── .husky/
│   └── pre-commit
├── .prettierrc
├── .solcover.js
├── .solhint.json
├── LICENSE
├── README.md
├── audits/
│   └── v1/
│       └── Consensys_Diligence.md
├── config/
│   └── PROD.env.sample
├── contracts/
│   ├── Factory.sol
│   ├── Wallet.sol
│   ├── hooks/
│   │   ├── WalletProxyHook.sol
│   │   └── interfaces/
│   │       └── IWalletProxy.sol
│   ├── interfaces/
│   │   ├── IERC1271Wallet.sol
│   │   ├── receivers/
│   │   │   ├── IERC1155Receiver.sol
│   │   │   ├── IERC223Receiver.sol
│   │   │   ├── IERC721Receiver.sol
│   │   │   └── IERC777Receiver.sol
│   │   └── tokens/
│   │       ├── IERC1155.sol
│   │       ├── IERC20.sol
│   │       └── IERC721.sol
│   ├── mocks/
│   │   ├── AlwaysRevertMock.sol
│   │   ├── CallReceiverMock.sol
│   │   ├── DelegateCallMock.sol
│   │   ├── ERC1155Mock.sol
│   │   ├── ERC165CheckerMock.sol
│   │   ├── ERC20Mock.sol
│   │   ├── ERC721Mock.sol
│   │   ├── GasBurnerMock.sol
│   │   ├── HookCallerMock.sol
│   │   ├── HookMock.sol
│   │   ├── LibBytesImpl.sol
│   │   ├── LibBytesPointerImpl.sol
│   │   ├── LibStringImp.sol
│   │   └── ModuleMock.sol
│   ├── modules/
│   │   ├── GuestModule.sol
│   │   ├── MainModule.sol
│   │   ├── MainModuleGasEstimation.sol
│   │   ├── MainModuleUpgradable.sol
│   │   ├── commons/
│   │   │   ├── Implementation.sol
│   │   │   ├── ModuleAuth.sol
│   │   │   ├── ModuleAuthConvenience.sol
│   │   │   ├── ModuleAuthFixed.sol
│   │   │   ├── ModuleAuthUpgradable.sol
│   │   │   ├── ModuleCalls.sol
│   │   │   ├── ModuleCreator.sol
│   │   │   ├── ModuleERC165.sol
│   │   │   ├── ModuleERC5719.sol
│   │   │   ├── ModuleExtraAuth.sol
│   │   │   ├── ModuleHooks.sol
│   │   │   ├── ModuleIPFS.sol
│   │   │   ├── ModuleNonce.sol
│   │   │   ├── ModuleOnlyDelegatecall.sol
│   │   │   ├── ModuleSelfAuth.sol
│   │   │   ├── ModuleStorage.sol
│   │   │   ├── ModuleUpdate.sol
│   │   │   ├── gas-estimation/
│   │   │   │   ├── ModuleIgnoreAuthUpgradable.sol
│   │   │   │   └── ModuleIgnoreNonceCalls.sol
│   │   │   ├── interfaces/
│   │   │   │   ├── IModuleAuth.sol
│   │   │   │   ├── IModuleAuthUpgradable.sol
│   │   │   │   ├── IModuleCalls.sol
│   │   │   │   ├── IModuleCreator.sol
│   │   │   │   ├── IModuleHooks.sol
│   │   │   │   └── IModuleUpdate.sol
│   │   │   └── submodules/
│   │   │       ├── auth/
│   │   │       │   ├── SequenceBaseSig.sol
│   │   │       │   ├── SequenceChainedSig.sol
│   │   │       │   ├── SequenceDynamicSig.sol
│   │   │       │   └── SequenceNoChainIdSig.sol
│   │   │       └── nonce/
│   │   │           └── SubModuleNonce.sol
│   │   └── utils/
│   │       ├── GasEstimator.sol
│   │       ├── MultiCallUtils.sol
│   │       ├── RequireUtils.sol
│   │       └── SequenceUtils.sol
│   ├── trust/
│   │   ├── Trust.sol
│   │   └── TrustFactory.sol
│   └── utils/
│       ├── LibAddress.sol
│       ├── LibBytes.sol
│       ├── LibBytesPointer.sol
│       ├── LibOptim.sol
│       ├── LibString.sol
│       └── SignatureValidator.sol
├── foundry.toml
├── foundry_test/
│   ├── base/
│   │   └── AdvTest.sol
│   ├── hooks/
│   │   └── WalletProxyHook.t.sol
│   ├── modules/
│   │   ├── commons/
│   │   │   ├── Implementation.t.sol
│   │   │   ├── ModuleCalls.t.sol
│   │   │   ├── ModuleERC5719.t.sol
│   │   │   ├── ModuleExtraAuth.t.sol
│   │   │   ├── ModuleIPFS.t.sol
│   │   │   ├── ModuleStorage.t.sol
│   │   │   └── submodules/
│   │   │       ├── auth/
│   │   │       │   ├── SequenceBaseSig.t.sol
│   │   │       │   ├── SequenceChainedSig.t.sol
│   │   │       │   ├── SequenceDynamicSig.t.sol
│   │   │       │   └── SequenceNoChainIdSig.t.sol
│   │   │       └── nonce/
│   │   │           └── SubModuleNonce.t.sol
│   │   └── utils/
│   │       ├── L2CompressorEncoder.sol
│   │       ├── L2CompressorHuff.t.sol
│   │       ├── L2CompressorHuffReadExecute.sol
│   │       ├── L2CompressorHuffReadFlag.t.sol
│   │       ├── L2CompressorHuffReadNonce.sol
│   │       ├── L2CompressorHuffReadTx.t.sol
│   │       ├── L2CompressorHuffReadTxs.t.sol
│   │       └── RequireUtils.t.sol
│   ├── trust/
│   │   ├── Trust.t.sol
│   │   └── TrustFactory.t.sol
│   └── utils/
│       ├── LibAddress.t.sol
│       ├── LibBytes.t.sol
│       ├── LibBytesPointer.t.sol
│       ├── LibOptim.t.sol
│       └── SignatureValidator.t.sol
├── funding.json
├── hardhat.config.ts
├── networks/
│   ├── arbitrum.json
│   ├── arbitrumGoerli.json
│   ├── arbitrumNova.json
│   ├── avalanche.json
│   ├── avalancheFuji.json
│   ├── bnb.json
│   ├── bnbTestnet.json
│   ├── gnosis.json
│   ├── goerli.json
│   ├── hardhat.json
│   ├── mainnet.json
│   ├── mumbai.json
│   ├── optimism.json
│   ├── polygon.json
│   └── polygonZkevm.json
├── package.json
├── remappings.txt
├── run_huff_tests.sh
├── src/
│   ├── Errors.huff
│   ├── L2Compressor.huff
│   ├── L2CompressorLib.huff
│   └── imps/
│       ├── L2CompressorImps.huff
│       ├── L2CompressorReadExecute.huff
│       ├── L2CompressorReadFlag.huff
│       ├── L2CompressorReadNonce.huff
│       ├── L2CompressorReadTx.huff
│       └── L2CompressorReadTxs.huff
├── test/
│   ├── ChainedSignatures.spec.ts
│   ├── ERC165.spec.ts
│   ├── Factory.spec.ts
│   ├── GasEstimation.spec.ts
│   ├── GuestModule.spec.ts
│   ├── LibBytes.spec.ts
│   ├── LibString.spec.ts
│   ├── MainModule.bench.ts
│   ├── MainModule.spec.ts
│   ├── MerkleSignatures.spec.ts
│   ├── MultiCallUtils.spec.ts
│   └── utils/
│       ├── contracts.ts
│       ├── imposter.ts
│       ├── index.ts
│       ├── sequence.ts
│       └── wallet.ts
├── tsconfig.json
├── typings/
│   ├── chai-bignumber.d.ts
│   ├── chai-bn.ts
│   └── truffle.d.ts
└── utils/
    ├── benchmarker.ts
    ├── config-loader.ts
    ├── deploy-contracts.ts
    └── workers/
        └── bench-worker.ts
Download .txt
SYMBOL INDEX (131 symbols across 13 files)

FILE: test/GasEstimation.spec.ts
  function txBaseCost (line 18) | function txBaseCost(data: ethers.BytesLike): number {

FILE: test/MainModule.bench.ts
  function report2 (line 10) | function report2(values: ethers.BigNumberish[]) {
  function report (line 20) | function report(test: string, values: ethers.BigNumberish[]) {

FILE: test/utils/contracts.ts
  function deploy (line 7) | async function deploy<Y extends ethers.BaseContract>(name: string, ...ar...
  function attach (line 13) | function attach<Y extends ethers.BaseContract>(name: string, address: st...
  type Adapter (line 17) | type Adapter<T extends ethers.BaseContract> = {
  function adapt (line 24) | function adapt<T extends ethers.BaseContract>(name: string): Adapter<T> {
  type ContractType (line 33) | type ContractType<T extends Adapter<any>> = T extends Adapter<infer U> ?...
  type SequenceContext (line 83) | type SequenceContext = {

FILE: test/utils/imposter.ts
  class Imposter (line 4) | class Imposter extends ethers.AbstractSigner implements StaticSigner {
    method random (line 5) | static random(identity: string | AnyStaticSigner) {
    method constructor (line 9) | constructor(
    method address (line 16) | get address() {
    method getAddress (line 20) | async getAddress(): Promise<string> {
    method signMessage (line 24) | signMessage(message: string | Uint8Array): Promise<string> {
    method signTypedData (line 28) | signTypedData(
    method signTransaction (line 36) | signTransaction(transaction: ethers.TransactionRequest): Promise<strin...
    method connect (line 40) | connect(provider: ethers.Provider): ethers.Signer {

FILE: test/utils/index.ts
  function bytes32toAddress (line 13) | function bytes32toAddress(bytes32: ethers.BytesLike): string {
  function shuffle (line 18) | function shuffle<T>(a: T[]): T[] {
  function randomHex (line 27) | function randomHex(length: number): string {
  function expectToBeRejected (line 31) | async function expectToBeRejected(promise: Promise<any>, error: string) {
  function expectStaticToBeRejected (line 39) | async function expectStaticToBeRejected(promise: Promise<any>, signature...
  function encodeError (line 98) | function encodeError(error: string): string {
  function xor (line 102) | function xor(a: any, b: any) {
  function interfaceIdOf (line 108) | function interfaceIdOf(int: ethers.Interface): string {
  function getSigHash (line 116) | function getSigHash(fragment: ethers.FunctionFragment): string {

FILE: test/utils/sequence.ts
  constant WALLET_CODE (line 4) | const WALLET_CODE = '0x603a600e3d39601a805130553df3363d3d373d3d3d363d305...
  type SignatureType (line 6) | enum SignatureType {
  type SignerLeaf (line 12) | type SignerLeaf = {
  type SubdigestLeaf (line 17) | type SubdigestLeaf = {
  type NestedLeaf (line 21) | type NestedLeaf = {
  type ConfigLeaf (line 27) | type ConfigLeaf = SubdigestLeaf | SignerLeaf | NestedLeaf
  type ImageHashNode (line 29) | type ImageHashNode = {
  type ConfigTopology (line 34) | type ConfigTopology = ImageHashNode | ConfigLeaf
  type WalletConfig (line 36) | type WalletConfig = {
  type SimplifiedNestedWalletConfig (line 42) | type SimplifiedNestedWalletConfig = {
  type SimplifiedWalletConfig (line 48) | type SimplifiedWalletConfig = {
  type SimplifiedConfigMember (line 54) | type SimplifiedConfigMember = SignerLeaf | SimplifiedNestedWalletConfig
  type Transaction (line 56) | type Transaction = {
  type SignaturePartType (line 65) | enum SignaturePartType {
  type SignaturePart (line 75) | type SignaturePart = {
  function applyTxDefault (line 81) | function applyTxDefault(
  function applyTxDefaults (line 98) | function applyTxDefaults(tx: Partial<Transaction>[], def?: Transaction):...
  function isConfigLeaf (line 111) | function isConfigLeaf(node: ConfigTopology): node is ConfigLeaf {
  function isSignerLeaf (line 115) | function isSignerLeaf(node: any): node is SignerLeaf {
  function isSubdigestLeaf (line 119) | function isSubdigestLeaf(node: ConfigTopology): node is SubdigestLeaf {
  function isNestedLeaf (line 123) | function isNestedLeaf(node: ConfigTopology): node is NestedLeaf {
  function legacyTopology (line 127) | function legacyTopology(leavesOrConfig: SimplifiedWalletConfig | ConfigT...
  function toTopology (line 140) | function toTopology(config: SimplifiedWalletConfig | SimplifiedNestedWal...
  function merkleTopology (line 157) | function merkleTopology(leavesOrConfig: SimplifiedWalletConfig | ConfigT...
  function optimize2SignersTopology (line 182) | function optimize2SignersTopology(config: SimplifiedWalletConfig): Confi...
  function leavesOf (line 190) | function leavesOf(topology: ConfigTopology): ConfigLeaf[] {
  function subdigestLeaves (line 198) | function subdigestLeaves(topology: ConfigTopology): string[] {
  function toSimplifiedConfig (line 204) | function toSimplifiedConfig(config: WalletConfig): SimplifiedWalletConfig {
  function hashNode (line 217) | function hashNode(node: ConfigTopology): string {
  function imageHash2 (line 236) | function imageHash2(threshold: ethers.BigNumberish, topology: ConfigTopo...
  function printTopology (line 241) | function printTopology(topology: ConfigTopology, threshold?: ethers.BigN...
  function addressOf (line 297) | function addressOf(factory: string, firstModule: string, imageHash: stri...
  function encodeNonce (line 309) | function encodeNonce(space: BigNumberish, nonce: BigNumberish) {
  function leafForAddressAndWeight (line 313) | function leafForAddressAndWeight(address: string, weight: ethers.BigNumb...
  function imageHash (line 317) | function imageHash(config: WalletConfig): string {
  function digestOf (line 327) | function digestOf(txs: Partial<Transaction>[], nonce: ethers.BigNumberis...
  function subdigestOf (line 333) | async function subdigestOf(wallet: string, digest: ethers.BytesLike, cha...
  function computeStorageKey (line 340) | function computeStorageKey(key: string, subkey?: string): string {
  type EncodingOptions (line 348) | type EncodingOptions = {
  function leftSlice (line 354) | function leftSlice(topology: ConfigTopology): ConfigTopology[] {
  type DecodedSignatureMember (line 369) | type DecodedSignatureMember = {
  class SignatureConstructor (line 377) | class SignatureConstructor {
    method constructor (line 380) | constructor(public disableTrim = false) {}
    method tryTrim (line 382) | tryTrim(): void {
    method appendPart (line 415) | appendPart(weight: ethers.BigNumberish, part: SignaturePart) {
    method appendNode (line 436) | appendNode(node: string) {
    method appendBranch (line 441) | appendBranch(branch: string) {
    method appendSubdigest (line 445) | appendSubdigest(subdigest: string) {
    method appendNested (line 449) | appendNested(branch: string, weight: ethers.BigNumberish, innerThresho...
    method encode (line 453) | encode(): string {
  function encodeSigners (line 513) | function encodeSigners(
  function encodeSignature (line 587) | function encodeSignature(

FILE: test/utils/wallet.ts
  type StaticSigner (line 23) | type StaticSigner = ethers.Signer & { address: string }
  type AnyStaticSigner (line 24) | type AnyStaticSigner = StaticSigner | SequenceWallet
  function isAnyStaticSigner (line 26) | function isAnyStaticSigner(s: any): s is AnyStaticSigner {
  constant LAST_CHECKPOINT (line 30) | let LAST_CHECKPOINT = 0
  function getCheckpoint (line 32) | function getCheckpoint() {
  type WalletOptions (line 43) | type WalletOptions = {
  type BasicWalletOptions (line 52) | type BasicWalletOptions = {
  type DetailedWalletOptions (line 61) | type DetailedWalletOptions = {
  type Weighted (line 68) | type Weighted<T> = { weight: number; value: T }
  function isWeighted (line 70) | function isWeighted<T>(w: any): w is Weighted<T> {
  function weightedVal (line 74) | function weightedVal<T>(w: Weighted<T> | T): T {
  function isSequenceSigner (line 78) | function isSequenceSigner(signer: ethers.Signer | SequenceWallet): signe...
  class SequenceWallet (line 84) | class SequenceWallet {
    method constructor (line 88) | constructor(public options: WalletOptions) {}
    method basicWallet (line 90) | static basicWallet(context: SequenceContext, opts?: Partial<BasicWalle...
    method detailedWallet (line 130) | static detailedWallet(context: SequenceContext, opts: DetailedWalletOp...
    method useAddress (line 155) | useAddress(address?: string) {
    method useConfig (line 159) | useConfig(of: SequenceWallet | WalletConfig) {
    method useSigners (line 164) | useSigners(signers: (ethers.Signer | SequenceWallet)[] | ethers.Signer...
    method useEncodingOptions (line 168) | useEncodingOptions(encodingOptions?: EncodingOptions) {
    method useChainId (line 172) | useChainId(chainId?: ethers.BigNumberish) {
    method config (line 176) | get config() {
    method signers (line 180) | get signers() {
    method address (line 184) | get address() {
    method getAddress (line 193) | getAddress() {
    method imageHash (line 197) | get imageHash() {
    method mainModule (line 201) | get mainModule() {
    method mainModuleUpgradable (line 205) | get mainModuleUpgradable() {
    method deploy (line 209) | async deploy() {
    method getNonce (line 217) | async getNonce(space: ethers.BigNumberish = 0) {
    method updateImageHash (line 221) | async updateImageHash(input: ethers.BytesLike | WalletConfig): Promise...
    method addExtraImageHash (line 232) | async addExtraImageHash(
    method clearExtraImageHashes (line 246) | async clearExtraImageHashes(imageHashes: (ethers.BytesLike | WalletCon...
    method signMessage (line 257) | async signMessage(message: ethers.BytesLike): Promise<string> {
    method signDigest (line 261) | async signDigest(digest: ethers.BytesLike): Promise<string> {
    method staticSubdigestSign (line 266) | staticSubdigestSign(subdigest: ethers.BytesLike, useNoChainId = true):...
    method signSubdigest (line 271) | async signSubdigest(subdigest: ethers.BytesLike): Promise<string> {
    method signTransactions (line 293) | async signTransactions(ptxs: Partial<Transaction>[], nonce?: ethers.Bi...
    method relayTransactions (line 302) | async relayTransactions(
    method sendTransactions (line 317) | async sendTransactions(

FILE: typings/chai-bignumber.d.ts
  type Assertion (line 13) | interface Assertion extends LanguageChains, NumericComparison, TypeCompa...

FILE: typings/chai-bn.ts
  type Equal (line 13) | interface Equal {
  type NumberComparer (line 16) | interface NumberComparer {

FILE: typings/truffle.d.ts
  type ArtifactsGlobal (line 4) | interface ArtifactsGlobal {

FILE: utils/benchmarker.ts
  class BufferSort (line 9) | class BufferSort {
    method constructor (line 13) | constructor(private onValue: (val: string) => void) {}
  function main (line 27) | async function main(args: {

FILE: utils/config-loader.ts
  type EthereumNetworksTypes (line 6) | type EthereumNetworksTypes =

FILE: utils/workers/bench-worker.ts
  function report2 (line 19) | function report2(values: ethers.BigNumberish[]) {
  method setup (line 30) | async setup(signing: number, idle: number, runs: number, topology: 'lega...
  method run (line 43) | async run() {
  type BenchWorker (line 87) | type BenchWorker = typeof worker
Condensed preview — 169 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (673K chars).
[
  {
    "path": ".eslintignore",
    "chars": 34,
    "preview": ".eslintrc.js\nnode_modules\nsrc/gen\n"
  },
  {
    "path": ".eslintrc.js",
    "chars": 1061,
    "preview": "const { off } = require(\"process\")\n\nmodule.exports = {\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecm"
  },
  {
    "path": ".gitattributes",
    "chars": 33,
    "preview": "*.sol linguist-language=Solidity\n"
  },
  {
    "path": ".github/actions/install-dependencies/action.yml",
    "chars": 877,
    "preview": "name: Setup Node and PNPM dependencies\n\nruns:\n  using: 'composite'\n\n  steps:\n    - name: Setup Node\n      uses: actions/"
  },
  {
    "path": ".github/workflows/ci.yml",
    "chars": 2467,
    "preview": "on: [push]\n\nname: ci\n\njobs:\n  benchmark:\n    name: Benchmark\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions"
  },
  {
    "path": ".gitignore",
    "chars": 194,
    "preview": ".vscode\n.devcontainer\nnode_modules/\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\nlerna-debug.log*\n\n*.js.map\nbuild\ncov"
  },
  {
    "path": ".gitmodules",
    "chars": 205,
    "preview": "[submodule \"lib/forge-std\"]\n\tpath = lib/forge-std\n\turl = https://github.com/foundry-rs/forge-std\n[submodule \"lib/foundry"
  },
  {
    "path": ".husky/pre-commit",
    "chars": 10,
    "preview": "pnpm test\n"
  },
  {
    "path": ".prettierrc",
    "chars": 154,
    "preview": "{\n  \"tabWidth\": 2,\n  \"useTabs\": false,\n  \"semi\": false,\n  \"singleQuote\": true,\n  \"trailingComma\": \"none\",\n  \"arrowParens"
  },
  {
    "path": ".solcover.js",
    "chars": 58,
    "preview": "module.exports = {\n  skipFiles: ['mocks', 'migrations']\n}\n"
  },
  {
    "path": ".solhint.json",
    "chars": 809,
    "preview": "{\n  \"extends\": \"solhint:recommended\",\n  \"rules\": {\n    \"quotes\": \"off\",\n    \"const-name-snakecase\": \"off\",\n    \"contract"
  },
  {
    "path": "LICENSE",
    "chars": 12049,
    "preview": "   Copyright (c) 2017-present Horizon Blockchain Games Inc.\n\n   Licensed under the Apache License, Version 2.0 (the \"Lic"
  },
  {
    "path": "README.md",
    "chars": 3138,
    "preview": "# Sequence Smart Wallet Contracts\n\nEthereum contracts for the Sequence Smart Wallet at [https://sequence.app](https://se"
  },
  {
    "path": "audits/v1/Consensys_Diligence.md",
    "chars": 285,
    "preview": "# Consensys Diligence report May 2020\n\n[View full report](https://diligence.consensys.net/audits/private/cnhjwtpa-horizo"
  },
  {
    "path": "config/PROD.env.sample",
    "chars": 47,
    "preview": "ETH_MNEMONIC=\"\"\nINFURA_API_KEY=\"\"\nETHERSCAN=\"\"\n"
  },
  {
    "path": "contracts/Factory.sol",
    "chars": 982,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./Wallet.sol\";\n\n\ncontract Factory {\n  error Depl"
  },
  {
    "path": "contracts/Wallet.sol",
    "chars": 2992,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n/**\n    Minimal upgradeable proxy implementation, delega"
  },
  {
    "path": "contracts/hooks/WalletProxyHook.sol",
    "chars": 393,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport {IWalletProxy} from './interfaces/IWalletProxy.so"
  },
  {
    "path": "contracts/hooks/interfaces/IWalletProxy.sol",
    "chars": 588,
    "preview": "// Copyright Immutable Pty Ltd 2018 - 2023\n// SPDX-License-Identifier: Apache 2.0\n// https://github.com/immutable/contra"
  },
  {
    "path": "contracts/interfaces/IERC1271Wallet.sol",
    "chars": 1613,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ninterface IERC1271Wallet {\n\n  /**\n   * @notice Verifies"
  },
  {
    "path": "contracts/interfaces/receivers/IERC1155Receiver.sol",
    "chars": 339,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ninterface IERC1155Receiver {\n  function onERC1155Receiv"
  },
  {
    "path": "contracts/interfaces/receivers/IERC223Receiver.sol",
    "chars": 164,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ninterface IERC223Receiver {\n  function tokenFallback(ad"
  },
  {
    "path": "contracts/interfaces/receivers/IERC721Receiver.sol",
    "chars": 193,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ninterface IERC721Receiver {\n  function onERC721Received"
  },
  {
    "path": "contracts/interfaces/receivers/IERC777Receiver.sol",
    "chars": 206,
    "preview": "// SPDX-License-Identifier: Apache-2.0\r\npragma solidity 0.8.18;\r\n\r\ninterface IERC777Receiver {\r\n    function tokensRecei"
  },
  {
    "path": "contracts/interfaces/tokens/IERC1155.sol",
    "chars": 1110,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ninterface IERC1155 {\n  function balanceOf(address account, uin"
  },
  {
    "path": "contracts/interfaces/tokens/IERC20.sol",
    "chars": 708,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ninterface IERC20 {\n  function totalSupply() external view retu"
  },
  {
    "path": "contracts/interfaces/tokens/IERC721.sol",
    "chars": 1061,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ninterface IERC721 {\n  function balanceOf(address owner) extern"
  },
  {
    "path": "contracts/mocks/AlwaysRevertMock.sol",
    "chars": 187,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ncontract AlwaysRevertMock {\n  fallback() external payab"
  },
  {
    "path": "contracts/mocks/CallReceiverMock.sol",
    "chars": 479,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ncontract CallReceiverMock {\n  uint256 public lastValA;\n"
  },
  {
    "path": "contracts/mocks/DelegateCallMock.sol",
    "chars": 591,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ncontract DelegateCallMock {\n  event Readed(uint256 _val"
  },
  {
    "path": "contracts/mocks/ERC1155Mock.sol",
    "chars": 2177,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract ERC1155Mock {\n  string public name = 'Mock ERC1155 To"
  },
  {
    "path": "contracts/mocks/ERC165CheckerMock.sol",
    "chars": 1585,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ncontract ERC165CheckerMock {\n  bytes4 constant InvalidI"
  },
  {
    "path": "contracts/mocks/ERC20Mock.sol",
    "chars": 1750,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract ERC20Mock {\n  string public name = 'Mock ERC20 Token'"
  },
  {
    "path": "contracts/mocks/ERC721Mock.sol",
    "chars": 2740,
    "preview": "// SPDX-License-Identifier: MIT\npragma solidity ^0.8.18;\n\ncontract ERC721Mock {\n  string public name = 'Mock ERC721 Toke"
  },
  {
    "path": "contracts/mocks/GasBurnerMock.sol",
    "chars": 353,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ncontract GasBurnerMock {\n  event ProvidedGas(uint256 _v"
  },
  {
    "path": "contracts/mocks/HookCallerMock.sol",
    "chars": 2166,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"../interfaces/receivers/IERC1155Receiver.sol\";\ni"
  },
  {
    "path": "contracts/mocks/HookMock.sol",
    "chars": 186,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ncontract HookMock {\n  function onHookMockCall(uint256 _"
  },
  {
    "path": "contracts/mocks/LibBytesImpl.sol",
    "chars": 641,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"../utils/LibBytes.sol\";\n\n\ncontract LibBytesImpl "
  },
  {
    "path": "contracts/mocks/LibBytesPointerImpl.sol",
    "chars": 933,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"../utils/LibBytesPointer.sol\";\n\n\ncontract LibByt"
  },
  {
    "path": "contracts/mocks/LibStringImp.sol",
    "chars": 705,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"../utils/LibString.sol\";\n\n\ncontract LibStringImp"
  },
  {
    "path": "contracts/mocks/ModuleMock.sol",
    "chars": 156,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ncontract ModuleMock {\n  event Pong();\n\n  function ping("
  },
  {
    "path": "contracts/modules/GuestModule.sol",
    "chars": 3334,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"../utils/LibOptim.sol\";\n\nimport \"./commons/submo"
  },
  {
    "path": "contracts/modules/MainModule.sol",
    "chars": 1557,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./commons/ModuleAuthFixed.sol\";\nimport \"./common"
  },
  {
    "path": "contracts/modules/MainModuleGasEstimation.sol",
    "chars": 3337,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./commons/gas-estimation/ModuleIgnoreAuthUpgrada"
  },
  {
    "path": "contracts/modules/MainModuleUpgradable.sol",
    "chars": 1808,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./commons/ModuleAuthUpgradable.sol\";\nimport \"./c"
  },
  {
    "path": "contracts/modules/commons/Implementation.sol",
    "chars": 869,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n/**\n * @dev Allows modules to access the implementation "
  },
  {
    "path": "contracts/modules/commons/ModuleAuth.sol",
    "chars": 6578,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"../../utils/LibBytes.sol\";\nimport \"../../interfa"
  },
  {
    "path": "contracts/modules/commons/ModuleAuthConvenience.sol",
    "chars": 1323,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./ModuleSelfAuth.sol\";\nimport \"./ModuleAuth.sol\""
  },
  {
    "path": "contracts/modules/commons/ModuleAuthFixed.sol",
    "chars": 2708,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./ModuleAuth.sol\";\nimport \"./ModuleUpdate.sol\";\n"
  },
  {
    "path": "contracts/modules/commons/ModuleAuthUpgradable.sol",
    "chars": 1738,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./interfaces/IModuleAuthUpgradable.sol\";\n\nimport"
  },
  {
    "path": "contracts/modules/commons/ModuleCalls.sol",
    "chars": 4374,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./ModuleSelfAuth.sol\";\nimport \"./ModuleStorage.s"
  },
  {
    "path": "contracts/modules/commons/ModuleCreator.sol",
    "chars": 1178,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./interfaces/IModuleCreator.sol\";\n\nimport \"./Mod"
  },
  {
    "path": "contracts/modules/commons/ModuleERC165.sol",
    "chars": 764,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\nabstract contract ModuleERC165 {\n  /**\n   * @notice Que"
  },
  {
    "path": "contracts/modules/commons/ModuleERC5719.sol",
    "chars": 503,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./ModuleIPFS.sol\";\n\nimport \"../../utils/LibStrin"
  },
  {
    "path": "contracts/modules/commons/ModuleExtraAuth.sol",
    "chars": 2509,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./ModuleAuth.sol\";\nimport \"./ModuleStorage.sol\";"
  },
  {
    "path": "contracts/modules/commons/ModuleHooks.sol",
    "chars": 5015,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./interfaces/IModuleHooks.sol\";\n\nimport \"./Modul"
  },
  {
    "path": "contracts/modules/commons/ModuleIPFS.sol",
    "chars": 1136,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./ModuleSelfAuth.sol\";\nimport \"./ModuleStorage.s"
  },
  {
    "path": "contracts/modules/commons/ModuleNonce.sol",
    "chars": 2077,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./ModuleStorage.sol\";\n\nimport \"./submodules/nonc"
  },
  {
    "path": "contracts/modules/commons/ModuleOnlyDelegatecall.sol",
    "chars": 421,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ncontract ModuleOnlyDelegatecall {\n  address private imm"
  },
  {
    "path": "contracts/modules/commons/ModuleSelfAuth.sol",
    "chars": 282,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ncontract ModuleSelfAuth {\n  error OnlySelfAuth(address "
  },
  {
    "path": "contracts/modules/commons/ModuleStorage.sol",
    "chars": 680,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\nlibrary ModuleStorage {\n  function writeBytes32(bytes32"
  },
  {
    "path": "contracts/modules/commons/ModuleUpdate.sol",
    "chars": 1681,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./interfaces/IModuleUpdate.sol\";\n\nimport \"./Impl"
  },
  {
    "path": "contracts/modules/commons/gas-estimation/ModuleIgnoreAuthUpgradable.sol",
    "chars": 768,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./../ModuleAuthUpgradable.sol\";\n\n\n/**\n  @notice "
  },
  {
    "path": "contracts/modules/commons/gas-estimation/ModuleIgnoreNonceCalls.sol",
    "chars": 985,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./../ModuleCalls.sol\";\n\nimport \"./../submodules/"
  },
  {
    "path": "contracts/modules/commons/interfaces/IModuleAuth.sol",
    "chars": 1467,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\nabstract contract IModuleAuth {\n  //                   "
  },
  {
    "path": "contracts/modules/commons/interfaces/IModuleAuthUpgradable.sol",
    "chars": 227,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ninterface IModuleAuthUpgradable {\n  /**\n   * @notice Re"
  },
  {
    "path": "contracts/modules/commons/interfaces/IModuleCalls.sol",
    "chars": 1329,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ninterface IModuleCalls {\n  // Events\n  event TxFailed(b"
  },
  {
    "path": "contracts/modules/commons/interfaces/IModuleCreator.sol",
    "chars": 386,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ninterface IModuleCreator {\n  error CreateFailed(bytes _"
  },
  {
    "path": "contracts/modules/commons/interfaces/IModuleHooks.sol",
    "chars": 962,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ninterface IModuleHooks {\n  // Errors\n  error HookAlread"
  },
  {
    "path": "contracts/modules/commons/interfaces/IModuleUpdate.sol",
    "chars": 734,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\nabstract contract IModuleUpdate {\n  // Errors\n  error I"
  },
  {
    "path": "contracts/modules/commons/submodules/auth/SequenceBaseSig.sol",
    "chars": 9544,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"../../../../utils/SignatureValidator.sol\";\nimpor"
  },
  {
    "path": "contracts/modules/commons/submodules/auth/SequenceChainedSig.sol",
    "chars": 4382,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./SequenceBaseSig.sol\";\n\nimport \"../../interface"
  },
  {
    "path": "contracts/modules/commons/submodules/auth/SequenceDynamicSig.sol",
    "chars": 913,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./SequenceBaseSig.sol\";\n\n\nlibrary SequenceDynami"
  },
  {
    "path": "contracts/modules/commons/submodules/auth/SequenceNoChainIdSig.sol",
    "chars": 620,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\nlibrary SequenceNoChainIdSig {\n\n  /**\n   * @notice Comp"
  },
  {
    "path": "contracts/modules/commons/submodules/nonce/SubModuleNonce.sol",
    "chars": 947,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\nlibrary SubModuleNonce {\n  // Nonce schema\n  //\n  // - "
  },
  {
    "path": "contracts/modules/utils/GasEstimator.sol",
    "chars": 386,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\ncontract GasEstimator {\n  function estimate(\n    addres"
  },
  {
    "path": "contracts/modules/utils/MultiCallUtils.sol",
    "chars": 2905,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"../commons/interfaces/IModuleCalls.sol\";\n\n\ncontr"
  },
  {
    "path": "contracts/modules/utils/RequireUtils.sol",
    "chars": 4420,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"../commons/ModuleNonce.sol\";\nimport \"../commons/"
  },
  {
    "path": "contracts/modules/utils/SequenceUtils.sol",
    "chars": 189,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./MultiCallUtils.sol\";\nimport \"./RequireUtils.so"
  },
  {
    "path": "contracts/trust/Trust.sol",
    "chars": 4686,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"../interfaces/IERC1271Wallet.sol\";\nimport \"../ut"
  },
  {
    "path": "contracts/trust/TrustFactory.sol",
    "chars": 816,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"./Trust.sol\";\n\n\ncontract TrustFactory {\n  functi"
  },
  {
    "path": "contracts/utils/LibAddress.sol",
    "chars": 589,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\nlibrary LibAddress {\n  /**\n   * @notice Will return tru"
  },
  {
    "path": "contracts/utils/LibBytes.sol",
    "chars": 2563,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\n/**\n * @title Library for reading data from bytes array"
  },
  {
    "path": "contracts/utils/LibBytesPointer.sol",
    "chars": 5636,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\n/**\n * @title Library for reading data from bytes array"
  },
  {
    "path": "contracts/utils/LibOptim.sol",
    "chars": 2588,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n/**\n * @title Library for optimized EVM operations\n * @a"
  },
  {
    "path": "contracts/utils/LibString.sol",
    "chars": 2605,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n/**\n * @title Library for string manipulation operations"
  },
  {
    "path": "contracts/utils/SignatureValidator.sol",
    "chars": 5362,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"../interfaces/IERC1271Wallet.sol\";\n\nimport \"./Li"
  },
  {
    "path": "foundry.toml",
    "chars": 154,
    "preview": "[profile.default]\nsrc = 'contracts'\nout = 'foundry_artifacts'\nlibs = [\"node_modules\", \"lib\"]\ntest = 'foundry_test'\n\nffi "
  },
  {
    "path": "foundry_test/base/AdvTest.sol",
    "chars": 5458,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"forge-std/Test.sol\";\n\n\ncontract AdvTest is Test "
  },
  {
    "path": "foundry_test/hooks/WalletProxyHook.t.sol",
    "chars": 1062,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport 'contracts/hooks/WalletProxyHook.sol';\nimport 'co"
  },
  {
    "path": "foundry_test/modules/commons/Implementation.t.sol",
    "chars": 2024,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/modules/commons/Implementation.sol\";\ni"
  },
  {
    "path": "foundry_test/modules/commons/ModuleCalls.t.sol",
    "chars": 10180,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/modules/commons/ModuleCalls.sol\";\nimpo"
  },
  {
    "path": "foundry_test/modules/commons/ModuleERC5719.t.sol",
    "chars": 1503,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/modules/commons/ModuleERC5719.sol\";\n\ni"
  },
  {
    "path": "foundry_test/modules/commons/ModuleExtraAuth.t.sol",
    "chars": 5906,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/modules/commons/ModuleExtraAuth.sol\";\n"
  },
  {
    "path": "foundry_test/modules/commons/ModuleIPFS.t.sol",
    "chars": 1550,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/modules/commons/ModuleIPFS.sol\";\n\nimpo"
  },
  {
    "path": "foundry_test/modules/commons/ModuleStorage.t.sol",
    "chars": 2462,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/modules/commons/ModuleStorage.sol\";\n\ni"
  },
  {
    "path": "foundry_test/modules/commons/submodules/auth/SequenceBaseSig.t.sol",
    "chars": 11675,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/modules/commons/submodules/auth/Sequen"
  },
  {
    "path": "foundry_test/modules/commons/submodules/auth/SequenceChainedSig.t.sol",
    "chars": 8020,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/modules/commons/submodules/auth/Sequen"
  },
  {
    "path": "foundry_test/modules/commons/submodules/auth/SequenceDynamicSig.t.sol",
    "chars": 1585,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/modules/commons/submodules/auth/Sequen"
  },
  {
    "path": "foundry_test/modules/commons/submodules/auth/SequenceNoChainIdSig.t.sol",
    "chars": 1594,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/modules/commons/submodules/auth/Sequen"
  },
  {
    "path": "foundry_test/modules/commons/submodules/nonce/SubModuleNonce.t.sol",
    "chars": 512,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/modules/commons/submodules/nonce/SubMo"
  },
  {
    "path": "foundry_test/modules/utils/L2CompressorEncoder.sol",
    "chars": 11227,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\n\nfunction requiredBytesFor(bytes32 value) pure returns ("
  },
  {
    "path": "foundry_test/modules/utils/L2CompressorHuff.t.sol",
    "chars": 9789,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport \"foundry_test/base/AdvTest.sol\";\n\nimport \"forge-"
  },
  {
    "path": "foundry_test/modules/utils/L2CompressorHuffReadExecute.sol",
    "chars": 4645,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport \"foundry_test/base/AdvTest.sol\";\n\nimport \"forge-"
  },
  {
    "path": "foundry_test/modules/utils/L2CompressorHuffReadFlag.t.sol",
    "chars": 32081,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport \"foundry_test/base/AdvTest.sol\";\n\nimport \"forge-"
  },
  {
    "path": "foundry_test/modules/utils/L2CompressorHuffReadNonce.sol",
    "chars": 1822,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport \"foundry_test/base/AdvTest.sol\";\n\nimport \"forge-"
  },
  {
    "path": "foundry_test/modules/utils/L2CompressorHuffReadTx.t.sol",
    "chars": 3257,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport \"foundry_test/base/AdvTest.sol\";\n\nimport \"forge-"
  },
  {
    "path": "foundry_test/modules/utils/L2CompressorHuffReadTxs.t.sol",
    "chars": 4295,
    "preview": "// SPDX-License-Identifier: UNLICENSED\npragma solidity ^0.8.13;\n\nimport \"foundry_test/base/AdvTest.sol\";\n\nimport \"forge-"
  },
  {
    "path": "foundry_test/modules/utils/RequireUtils.t.sol",
    "chars": 5341,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/Factory.sol\";\nimport \"contracts/module"
  },
  {
    "path": "foundry_test/trust/Trust.t.sol",
    "chars": 28342,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/trust/Trust.sol\";\nimport \"contracts/in"
  },
  {
    "path": "foundry_test/trust/TrustFactory.t.sol",
    "chars": 1843,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/trust/TrustFactory.sol\";\n\nimport \"foun"
  },
  {
    "path": "foundry_test/utils/LibAddress.t.sol",
    "chars": 379,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/utils/LibAddress.sol\";\n\nimport \"foundr"
  },
  {
    "path": "foundry_test/utils/LibBytes.t.sol",
    "chars": 3385,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/utils/LibBytes.sol\";\n\nimport \"foundry_"
  },
  {
    "path": "foundry_test/utils/LibBytesPointer.t.sol",
    "chars": 5220,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/utils/LibBytes.sol\";\nimport \"contracts"
  },
  {
    "path": "foundry_test/utils/LibOptim.t.sol",
    "chars": 1606,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/utils/LibOptim.sol\";\n\nimport \"foundry_"
  },
  {
    "path": "foundry_test/utils/SignatureValidator.t.sol",
    "chars": 7247,
    "preview": "// SPDX-License-Identifier: Apache-2.0\npragma solidity 0.8.18;\n\nimport \"contracts/utils/SignatureValidator.sol\";\n\nimport"
  },
  {
    "path": "funding.json",
    "chars": 109,
    "preview": "{\n  \"opRetro\": {\n    \"projectId\": \"0x62408999652f3bfa1be746d256bf5a4eb4719b993d40f07d2d60aaebee015018\"\n  }\n}\n"
  },
  {
    "path": "hardhat.config.ts",
    "chars": 1890,
    "preview": "import { HardhatUserConfig, task } from 'hardhat/config'\nimport { networkConfig } from './utils/config-loader'\n\nimport '"
  },
  {
    "path": "networks/arbitrum.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/arbitrumGoerli.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/arbitrumNova.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/avalanche.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/avalancheFuji.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/bnb.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/bnbTestnet.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/gnosis.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/goerli.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/hardhat.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/mainnet.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/mumbai.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/optimism.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/polygon.json",
    "chars": 639,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "networks/polygonZkevm.json",
    "chars": 534,
    "preview": "[\n  {\n    \"contractName\": \"WalletFactory\",\n    \"address\": \"0xFaA5c0b14d1bED5C888Ca655B9a8A5911F78eF4A\"\n  },\n  {\n    \"con"
  },
  {
    "path": "package.json",
    "chars": 3126,
    "preview": "{\n  \"name\": \"@0xsequence/wallet-contracts\",\n  \"version\": \"3.0.1\",\n  \"private\": true,\n  \"license\": \"Apache-2.0\",\n  \"scrip"
  },
  {
    "path": "remappings.txt",
    "chars": 69,
    "preview": "ds-test/=lib/forge-std/lib/ds-test/src/\nforge-std/=lib/forge-std/src/"
  },
  {
    "path": "run_huff_tests.sh",
    "chars": 443,
    "preview": "#!/bin/bash\n\nfor file in $(find ./src -type f -name '*.huff'); do\n    echo \"Testing $file...\"\n    output=$(huffc \"$file\""
  },
  {
    "path": "src/Errors.huff",
    "chars": 5683,
    "preview": "/// @title Errors\n/// @notice SPDX-License-Identifier: MIT\n/// @author jtriley.eth\n/// @author clabby <https://github.co"
  },
  {
    "path": "src/L2Compressor.huff",
    "chars": 4631,
    "preview": "#include \"./L2CompressorLib.huff\"\n\n\n#define jumptable SELECTORS_TABLE {\n  execute_transaction          // 0x00\n  execute"
  },
  {
    "path": "src/L2CompressorLib.huff",
    "chars": 97011,
    "preview": "#include \"./Errors.huff\"\n\n#define constant ADDR_BYTES_STORAGE = 0x00\n#define constant FMS = 0xa0\n\n#define constant FLAG_"
  },
  {
    "path": "src/imps/L2CompressorImps.huff",
    "chars": 1534,
    "preview": "#include \"../L2CompressorLib.huff\"\n\n#define function testLoadDynamicSize(bytes32 _a, bytes32 _b, uint256, uint256) view "
  },
  {
    "path": "src/imps/L2CompressorReadExecute.huff",
    "chars": 789,
    "preview": "#include \"../L2CompressorLib.huff\"\n\n#define constant FMS = 0xa0\n\n// Function Dispatching\n#define macro MAIN() = takes (1"
  },
  {
    "path": "src/imps/L2CompressorReadFlag.huff",
    "chars": 771,
    "preview": "#include \"../L2CompressorLib.huff\"\n\n#define constant FMS = 0xa0\n\n// Function Dispatching\n#define macro MAIN() = takes (1"
  },
  {
    "path": "src/imps/L2CompressorReadNonce.huff",
    "chars": 783,
    "preview": "#include \"../L2CompressorLib.huff\"\n\n#define constant FMS = 0xa0\n\n// Function Dispatching\n#define macro MAIN() = takes (1"
  },
  {
    "path": "src/imps/L2CompressorReadTx.huff",
    "chars": 789,
    "preview": "#include \"../L2CompressorLib.huff\"\n\n#define constant FMS = 0xa0\n\n// Function Dispatching\n#define macro MAIN() = takes (1"
  },
  {
    "path": "src/imps/L2CompressorReadTxs.huff",
    "chars": 790,
    "preview": "#include \"../L2CompressorLib.huff\"\n\n#define constant FMS = 0xa0\n\n// Function Dispatching\n#define macro MAIN() = takes (1"
  },
  {
    "path": "test/ChainedSignatures.spec.ts",
    "chars": 5344,
    "preview": "import { expect } from 'chai'\nimport { ethers } from 'ethers'\nimport { expectToBeRejected } from './utils'\nimport { depl"
  },
  {
    "path": "test/ERC165.spec.ts",
    "chars": 2407,
    "preview": "import { ethers } from 'ethers'\nimport { ContractType, deploySequenceContext, ERC165CheckerMock, SequenceContext } from "
  },
  {
    "path": "test/Factory.spec.ts",
    "chars": 2437,
    "preview": "import { ethers } from 'ethers'\n\nimport { ethers as hethers } from 'hardhat'\nimport { addressOf } from './utils/sequence"
  },
  {
    "path": "test/GasEstimation.spec.ts",
    "chars": 13444,
    "preview": "import { ethers } from 'ethers'\nimport { expect } from './utils'\n\nimport {\n  CallReceiverMock,\n  ContractType,\n  deployS"
  },
  {
    "path": "test/GuestModule.spec.ts",
    "chars": 3503,
    "preview": "import { expect, expectToBeRejected } from './utils'\nimport { ethers as hethers } from 'hardhat'\nimport { ethers } from "
  },
  {
    "path": "test/LibBytes.spec.ts",
    "chars": 7120,
    "preview": "import { ethers } from 'ethers'\n\nimport { expect, expectStaticToBeRejected, randomHex } from './utils'\nimport { Contract"
  },
  {
    "path": "test/LibString.spec.ts",
    "chars": 4115,
    "preview": "import { ethers } from 'ethers'\n\nimport { expect, expectStaticToBeRejected, randomHex } from './utils'\nimport { Contract"
  },
  {
    "path": "test/MainModule.bench.ts",
    "chars": 6025,
    "preview": "import { ethers } from 'ethers'\n\nimport { deploySequenceContext, SequenceContext } from './utils/contracts'\nimport { Seq"
  },
  {
    "path": "test/MainModule.spec.ts",
    "chars": 82285,
    "preview": "import { ethers } from 'ethers'\nimport { ethers as hethers } from 'hardhat'\n\nimport { bytes32toAddress, getChainId, expe"
  },
  {
    "path": "test/MerkleSignatures.spec.ts",
    "chars": 956,
    "preview": "import { ethers } from 'ethers'\nimport { deploySequenceContext, SequenceContext } from './utils/contracts'\nimport { lega"
  },
  {
    "path": "test/MultiCallUtils.spec.ts",
    "chars": 10805,
    "preview": "import { ethers } from 'ethers'\n\nimport { ethers as hethers } from 'hardhat'\nimport { getChainId, encodeError, expect, e"
  },
  {
    "path": "test/utils/contracts.ts",
    "chars": 3467,
    "preview": "import { ethers } from 'ethers'\nimport { ethers as hethers } from 'hardhat'\nimport * as t from '../../gen/typechain'\n\nco"
  },
  {
    "path": "test/utils/imposter.ts",
    "chars": 1156,
    "preview": "import { ethers } from 'ethers'\nimport { AnyStaticSigner, StaticSigner } from './wallet'\n\nexport class Imposter extends "
  },
  {
    "path": "test/utils/index.ts",
    "chars": 3871,
    "preview": "import * as chai from 'chai'\nimport chaiAsPromised from 'chai-as-promised'\nimport chaiString from 'chai-string'\nimport {"
  },
  {
    "path": "test/utils/sequence.ts",
    "chars": 18449,
    "preview": "import { BigNumberish, BytesLike, ethers, Wallet } from 'ethers'\nimport { getChainId } from '.'\n\nexport const WALLET_COD"
  },
  {
    "path": "test/utils/wallet.ts",
    "chars": 9843,
    "preview": "import { ethers, Overrides } from 'ethers'\nimport { ethers as hethers } from 'hardhat'\nimport { shuffle } from '.'\nimpor"
  },
  {
    "path": "tsconfig.json",
    "chars": 901,
    "preview": "{\n  \"compilerOptions\": {\n    \"target\": \"es2020\",\n    \"module\": \"commonjs\",\n    \"moduleResolution\": \"node\",\n    \"sourceMa"
  },
  {
    "path": "typings/chai-bignumber.d.ts",
    "chars": 354,
    "preview": "/// <reference types=\"chai\" />\n\ndeclare module 'chai-bignumber' {\n  function chaiBignumber(bignumber: any): (chai: any, "
  },
  {
    "path": "typings/chai-bn.ts",
    "chars": 300,
    "preview": "/* eslint-disable */\n/// <reference types=\"chai\" />\n\ndeclare module 'chai-bn' {\n  function chaiBN(bignumber: any): (chai"
  },
  {
    "path": "typings/truffle.d.ts",
    "chars": 307,
    "preview": "declare module 'truffle' {\n  import * as truffle from 'truffle-contract'\n\n  interface ArtifactsGlobal {\n    require<A>(n"
  },
  {
    "path": "utils/benchmarker.ts",
    "chars": 3661,
    "preview": "\nimport { spawn, Worker, Pool } from \"threads\"\nimport { BenchWorker } from \"./workers/bench-worker\"\n\nimport { task } fro"
  },
  {
    "path": "utils/config-loader.ts",
    "chars": 3521,
    "preview": "import * as dotenv from 'dotenv'\nimport * as path from 'path'\nimport { HttpNetworkConfig } from 'hardhat/types'\nimport {"
  },
  {
    "path": "utils/deploy-contracts.ts",
    "chars": 7005,
    "preview": "import { network, run, tenderly, ethers as hethers } from 'hardhat'\nimport ora from 'ora'\n\nimport {\n  MainModule__factor"
  },
  {
    "path": "utils/workers/bench-worker.ts",
    "chars": 2428,
    "preview": "import { deploySequenceContext, SequenceContext } from '../../test/utils/contracts'\nimport { expose } from 'threads/work"
  }
]

About this extraction

This page contains the full source code of the 0xsequence/wallet-contracts GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 169 files (625.7 KB), approximately 179.1k tokens, and a symbol index with 131 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!