[
  {
    "path": ".github/workflows/dependency-review.yml",
    "content": "name: Dependency Review\non:\n  - pull_request\n\npermissions:\n  contents: read\n  pull-requests: write\n\njobs:\n  dependency-review:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout Repository\n        uses: actions/checkout@v5\n      - name: Dependency Review\n        uses: actions/dependency-review-action@v4\n        with:\n          comment-summary-in-pr: on-failure\n          fail-on-severity: moderate\n          license-check: false\n"
  },
  {
    "path": ".gitignore",
    "content": "momoka-node/node_modules\nmomoka-node/.env\nmomoka-node/coverage\nmomoka-node/coverage.json\nmomoka-node/lib/\nmomoka-node/database/*\nmomoka-node/da-verifier-database/*\n.DS_Store\nmomoka-node/cache/*\nmomoka-node/src/__PLAYGROUND__/*\nmomoka-node/lens__da/*\n.vscode\n.idea\nmomoka-node/.env.test\nmomoka-rs/target/*\n"
  },
  {
    "path": "README.md",
    "content": "# Momoka\n\n<img src=\"./images/logo.png\" />\n\nNot supported anymore but be our guest to fork.\n\n## Disclaimer\n\nWe would like to emphasize that this project is currently in its beta phase and incorporates new, innovative technology. As with any cutting-edge solution, there may be potential challenges or undiscovered issues that could arise during its initial stages. We are committed to continually refining and improving our offering, and we appreciate your understanding and patience as we work diligently to perfect this technology. Please feel free to provide feedback or report any issues, as your input is invaluable in helping us enhance the user experience and overall functionality of our project.\n\n# Momoka explorer\n\nYou can explore all momoka transactions on the explorer [here](https://momoka.lens.xyz). It is also open-source https://github.com/lens-protocol/momoka-explorer.\n\n<img src=\"./images/momoka-explorer.jpg\" />\n\n# Momoka Verifier\n\nThe Momoka Verifier enables you to operate a trustless verifier node that validates LENS DA publications in real-time. Additionally, it can serve as an indexer, allowing you to stream and index the data yourself. This open-source solution relies exclusively on software that you can run independently, without any dependency on LENS. This ensures that even if LENS were to cease operation, you would retain access to your content, maintain proof of ownership, and continue to utilize it, all thanks to a decentralized data availability storage layer.\n\nFor information on how to run this software, please refer to the [Technical code and how to run a verifier](#technical-code-and-how-to-run-a-verifier) section.\n\n## What is DA?\n\nDA stands for Data Availability. It refers to the concept of storing data in a decentralized availability layer, which is more cost-effective than storing it on an EVM chain. The DA has no latency, meaning the data is produced and queryable instantly, in contrast to IPFS and EVM chains, which always have latency until they are considered complete. We utilize Arweave and Bundlr for this purpose. Arweave is a decentralized, permanent storage network with over 100 nodes in operation (as writing this documentation); it is being increasingly adopted by various NFT projects. Bundlr enhances Arweave's scalability while providing DA guarantees, enabling the use of EVM wallets to save DA logic and serving as a tool to rapidly push data to Arweave. DA can be used to store actions like posts, comments, mirrors, and more; initially, we are focusing on publications. The goal is to keep the DA layer affordable and scalable while still verifying transactions on Polygon using EVM simulations. DA requires a one-time payment for data storage and is backed by mathematical and hardware history guarantees.\n\nUsing this software, you can verify that a particular action would have been executed on-chain. The approach involves performing the same signing actions as you would on an EVM chain, but without actually sending the transaction (which consumes gas to store in the EVM state). Instead, you create a DA standard and save it on a DA layer, complete with proofs and all the required information. This enables ANYONE to cross-check the data, providing 100% proof that the action must have been performed by someone capable of creating the transaction signature and submitting it. This can be demonstrated by simulating the transaction. This approach allows LENS to scale while maintaining the core values of \"ownership\" and \"trust\" provided by the blockchain.\n\n## Why do we need to use DA?\n\nEVM can store state indefinitely, but at a cost; blockchains were designed for trustless transactional systems. EVM is secured by the network and mined into the chain; the data on-chain is immutable and verifiable at any time, ensuring trust. However, storing data on-chain is expensive, and EVM machines can only process a limited number of transactions per block based on maximum gas limits. Polygon is a shared block space; and at the moment has challenges scaling beyond 50-100 TPS. With 2-second block times, some latency is unavoidable, and max gas limits per block make scaling challenging, if not impossible. For context, Twitter experiences peak rates of 25,000 TPS; while LENS may not require this level of capacity yet, scalability is a critical consideration. This is where DA layers come in; they offer a more affordable solution for storing data with a one-time payment, backed by mathematical guarantees and a history of decreasing hardware costs over time. Moreover, these DA layers are decentralized, preserving this aspect of the system. DA enables scalability beyond 25,000 TPS, and even more; if we aim to revolutionize the world of core social ownership, we must be able to scale accordingly.\n\n## What are transactions on EVM machines?\n\nA transaction on an EVM machine alters some form of state; it is signed by the wallet's private key and then transmitted to the network. The network verifies the signature and executes the transaction, which contains logic that can either succeed or revert. If the transaction reverts, it is not included in the new block; if it succeeds, it is incorporated into the new block and confirmed by other miners. Miners are incentivized to perform these confirmations. This process ensures that transactions cannot be \"faked,\" as they require a valid signature from a trusted key. Furthermore, a transaction can only succeed or revert—nothing more, nothing less. As the EVM progresses block by block and updates the state each time, it raises the question: what if you performed all steps of a transaction, except actually sending it, for actions that don't involve transferring funds or trustless executions?\n\n## How can DA and EVM work together?\n\nLENS is deployed on Polygon, an EVM-based platform. All actions—such as posts, comments, mirrors, follows, and collects are transactions that are built, signed, and sent to be stored on the EVM machine. In the new system, transactions are still built and require a signature from a wallet that would pass the state on-chain, but they are not actually sent. Instead, the transaction signature and typed data are used to create DA metadata, which is then transmitted to a DA layer containing information such as block number, signed typed data, transaction signature, and other crucial details. This data is structured in a way that can be fully verified with just having an archive node.\n\nEVM machines function as large state machines. The EVM JSON-RPC methods allow you to simulate transactions using `eth_call`, determining the outcome of a transaction without actually sending it. You can specify a block number to run the simulation and use the signed typed data transaction with the typed data. This can be done with every `withSig` method on the LENS contracts. With just a Polygon node, anyone can verify that the data on the DA layer is accurate and would have been valid at that point in time. Since the typed data contains expiry times and nonces, it can be proven in a secure manner and can not be submitted by anyone else, edge cases around this are huge reorg ranges which we cover below.\n\nThe advantage of this approach is that the data is stored on a decentralized layer, meaning that no centralized entity controls the content. Users retain ownership of their publications, and if any part of LENS were to disappear, all the data would remain verifiable, accessible, and usable by anyone. This demonstrates the power of decentralization, ensuring that users' data cannot be taken away from them.\n\n## What does this mean?\n\nThis approach allows LENS to scale to a lot higher TPS, which is currently unattainable with an EVM chain, while also providing a more cost-effective solution. This can be achieved without compromising the core ownership of the social graph, and the indexing process remains familiar for app developers. Using this system is optional; those who prefer can continue to store everything on Polygon. However, if a publication doesn't require the power of a trustless execution layer, there's no need to use the EVM state.\n\n## Momoka vs polygon side by side\n\nHere are diagrams that show how a transaction would look like on Polygon versus a transaction using the DA layer. These diagrams are meant to provide a simplified high-level overview of how the transactions work, while more detailed information is provided below with all the necessary technical details.\n\n### Polygon\n\n<img src=\"./images/current-polygon-flow.jpg\" />\n\n### Momoka\n\n<img src=\"./images/momoka-flow.jpg\" />\n\n## Comparison\n\n<img src=\"./images/tech-comparison.jpg\" />\n\nThe reason momoka security is medium and not high is that in theory a submitter could refuse to process transactions from certain users even though validators could do this as well as we only have 1 for now the fix is more. As we increase more submitters this comes down, also the bad submitters could in theory flood the system without any slashing mechanism. This is a problem that will be solved in the future.\n\nWe'd like to emphasize that while using Momoka, you can enjoy the benefits of finality, scalability, and cost-effectiveness. However, there is a slight tradeoff in terms of security, especially until we have many verifiers and submitters in the network. This is similar to what would happen to Ethereum's security if it lost all its validators. It's a tradeoff we're willing to make for now during our beta phase. We firmly believe that the advantages of the DA outweigh the disadvantages, even though we cannot start fully decentralized. Nevertheless, we're committed to working towards that goal with momoka.\n\n## Hyperscale\n\n<img src=\"./images/hyperscale-for-data.jpg\" />\n\n## Momoka Submitters\n\nTo maintain trust, submitters must be held accountable for their actions and face potential penalties for misconduct. Initially, the submitter whitelist will consist of a single address owned by LENS. As the approach is proven, the system can be expanded to allow anyone to become a submitter, with incentives for good behavior and penalties for bad actors. If submitters have nothing to lose, they could flood the system with invalid submissions, overwhelming verifiers and causing delays. During the beta phase, LENS will be responsible for correcting any errors, with bug bounties planned for the post-beta period. Ultimately, the goal is to have multiple submitters contributing to the system. It's important to note that certain errors, such as `UNKNOWN`, `CAN_NOT_CONNECT_TO_BUNDLR`, `BLOCK_CANT_BE_READ_FROM_NODE`, `DATA_CANT_BE_READ_FROM_NODE`, and `SIMULATION_NODE_COULD_NOT_RUN`, `POTENTIAL_REORG` are related to third-party software issues and not considered critical verifier errors. The verifier will retry these errors later to see if they still pass. Over time, the entire system could become decentralized. For now, this beta approach represents the first attempt at scaling using a hybrid module model.\n\n### Momoka Submitters' responsibilities\n\nSubmitters are responsible for validating, building up DA metadata, and submitting it to Arweave/Bundlr. After generating proofs with the DA submission, the data is uploaded to Arweave via Bundlr, with an instantaneous response. The submitter must provide proofs that anyone can contest. Verifier software listens for DA publications sent from whitelisted submitter addresses and verifies their validity.\n\n### Momoka Submitter flow\n\nThe flow diagram shows the submitter flows in detail; the first submitter will be within the LENS API to allow for easy integration for all.\n\n<img src=\"./images/submitter-flow.jpg\" />\n\n### Momoka Future of decentralised submitters\n\nThis is a rough look at how this could work in the future in a trustless manner. This is not the final solution but a rough idea of how it could work on a very high-level vision.\n\n<img src=\"./images/decentralized-submitters.jpg\" />\n\n## Momoka Verifiers\n\nVerifiers are tasked with monitoring DA publications from submitters and confirming their validity. They must follow specific criteria when evaluating incoming publications, with the primary goal of ensuring the submitter is truthful. Anyone can run a verifier using open-source software and a few commands. The verifier utilizes LevelDB for quick storage of passed results. The code has the capability to use a forked archive node with Foundry's `anvil` for local machine execution. However, for optimal speed, it is recommended to use an archive node directly (Alchemy is suggested but not required). All that's needed to run a verifier is an archive node.\n\n## Momoka Current limitations with DA publications\n\n- DA publications must use the `RevertCollectModule` and no `ReferenceModule`. This will be addressed in a future release.\n- For now, DA comments can only be added to other DA publications; they cannot be mixed. This limitation will be explored after the v1 launch.\n- DA mirrors can only mirror DA publications, not Polygon publications. This issue will be addressed post-v1 launch.\n- While it's not possible to prove DA publications on other DA publications on Polygon (as they are not on-chain), it's still possible to verify the signatures and transactions as valid. However, simulations cannot be executed in this scenario.\n- When verifying a submission, the pointer is checked as well. Only the first pointer is checked, not unlimited pointers, as the other verifications would have been done by the verifier.\n\n## Compatibility with signature-free transactions\n\nA top-class UX is essential for LENS users. DA publications work with the dispatcher, which can post, mirror, or comment on users' behalf. If enabled, this will pass state checks. The LENS contract logic states that if the dispatcher signs on behalf of the user, it will result in a valid transaction. Users who don't want to trust the dispatcher can still sign the typed data with their wallet and submit it through the submitter. This process is similar to the current flow, but the transaction is sent to a submitter instead of a Polygon node.\n\n## Gasless transactions\n\nDA operations don't require gas, making them free to use. The app still needs to upload the contentURI to a resolvable location, the submitter pays for storage of DA metadata on Arweave/Bundlr, which is significantly cheaper than EVM gas prices (up to 1000x cheaper).\n\n## Timestamp proofs for picking the block number\n\nYou might be concerned that a submitter could deceive about which block to submit on, but that's where Bundlr timestamp proofs come into play. In addition, each signature has a deadline that corresponds to the timestamp of an already mined block, rendering the signature invalid if sent. Bundlr enables you to request a timestamp proof that returns the current timestamp while storing it, allowing anyone to verify that the time was generated by them. This becomes our source of truth for determining the appropriate block number to use; we should use the block number closest to the timestamp generated by Bundlr. It's important to note that latency will inevitably occur due to node software, so if it selects a block number and, upon verification, it is one behind, we consider this an acceptable threshold.\n\n## Handling reorgs\n\nA reorg on the EVM chain occurs when the blockchain structure changes, often due to a consensus failure or attack. This can lead to previously confirmed transactions becoming unconfirmed, and vice versa. It has significant security implications, making it crucial to be aware of the potential for reorgs and take measures to mitigate their impact. Developers at Polygon and other organizations working on EVM software are striving to reduce the frequency and depth of reorgs, making the issue less concerning. As a general precaution, waiting before considering a transaction final, much like how centralized exchanges operate, is the safest approach - the longer the wait, the lower the risk of a reorg affecting the transaction. In Momoka's first beta version, users cannot mix DA actions with EVM on-chain actions, which was implemented intentionally to simplify handling reorgs.\n\nCurrently, the validator doesn't recheck proofs once they are validated, as its primary objective is to validate as quickly as possible for the initial proof. However, as we start integrating DA actions with EVM on-chain actions, we will need to incorporate reorg handling and enable the verifier to recheck intelligently.\n\nFor now, any reorg handling or rechecking must be performed outside of the validator software. For example, the LENS API also monitors reorgs and re-validates proofs if a reorg affects any DA actions.\n\nIf a transaction is part of a reorg and ends up in a different block or not included at all, the proofs should be re-validated using the new blockchain state, ensuring their validity despite the reorg.\n\nAs we are not mixing and matching actions we remove a lot of the issues but not all, the edge cases that could cause issues are situations where for example someone sets a dispatcher and then straight away performs an DA action that has the dispatcher sign on their behalf, and then a reorg follows. If the transaction which adds the dispatcher to the profile is not resubmitted or is resubmitted at a higher block number, the proofs would fail. In that case, rerunning the proofs would return a `POTENTIAL_REORG` error which is not \"bad\" in terms of a submitter doing wrong as they could not of predicted it, you can handle this then as needed. Once we start integrating the cross actions, we will handle such cases within the validator.\n\nA reorg of the blockchain can potentially affect the signing expiry of transactions. In the unlikely scenario of a severe reorg where time goes backwards on a block, it's conceivable that a transaction could be submitted to the chain that you never intended to. While this is a highly improbable edge case, it's essential to be aware of the possibility. As we embark on building the on-chain publications and DA publication connection, we'll delve deeper into these complex topics.\n\n## Future of Momoka\n\nAs we said above this is very much in BETA and as we learn, shape and grow the solution we envision the architecture will end up looking something like this, with decentralised submitters and verifiers.\n\n<img src=\"./images/momoka-network.jpg\" />\n\n## DA publication metadata\n\nMomoka verifier supports both v1 and v2 publications.\nWe will show you a few examples of the `DA` metadata and then explain each field.\n\n### Post v1 example\n\n```js\n{\n  signature:'0x87866d620636f62aa3930d8c48be37dac77f96f30a9e06748491934fef75e7884a193d59fc486da3ea35f991bbd37a04ea4997e47f191d626ad2b601e3cc57a71c',\n  dataAvailabilityId: '951a2a24-46fd-4306-8c31-46a8318a905e',\n  type: MomokaActionTypes.POST_CREATED,\n  timestampProofs: {\n    type: MomokaProvider.BUNDLR,\n    hashPrefix: '1',\n    response: {\n      id: 'f7_YMkEqiALN9PCtK5LXxFDlc3EEi20-DWl57KxDMbw',\n      timestamp: 1674736509185,\n      version: '1.0.0',\n      public:\n        'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n      signature:\n        'Requv25_byuhK_k0JPz2tjKLhmqUv1XGt4My88utf8AHpl8awJKPMUQV3LJIQABMXf9ZsM2RZNiPhKEilkefGD-fTqkZZI5ybHooP8hc-lx2mAdM0XfCw-SC-yhdDU3OoOat7bwVy0HvOJm8xc6HpqgdbnTotX3LuPAo_xEV5GxrB5giK1IY8ZBJEsIjZw6okSzEStfmm94zAG44SmtTDXJk0IpeBpQiiZks63quZkPETGR9nfYl9-5D4UjQZHsx1eqV_9Pa4vYMOnTXD5LB8ysi2C576QjJAFICEZtRF2rXyZm1yfWBY8ODrnoZx-RBB5pqAwqrwA4DBI_UBHmbB7lL_3DK4911bZbC03T1KUw5QZn6eWjnoyxIv_UG9B3Bht0UDPIgGXA2tKeUsdrrh2JPAImZIYXEhC5ZWqn-K4TZa586sGwpQVfHFvCuCA-9X6GspXKDqlqbys6sZk70OOhM4827JIs9dw_Hw8rwsPsGIJjP99x2iOnyH8FQynbW8TCnGQcsO7Xevj-1PGnIAsXqQO6E9_NkYAf8LSfsilY63ZhVNPgLnSS2BAR-28SpHW4GjXtN_nVzE1CoLmL3nczMqHTiZ-xalo_enYg0Ydx-ZqHF7cPrB5rQmR_uB_7zPKK5WgStxwVjHRBJ8MLxmW0Sylzf9K6IwwFy50klQHY',\n      deadlineHeight: 1106524,\n      block: 1106524,\n      validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n      signature:\n        '0xa3a969bd1ecdf7ca416340b513fd751df446b922809bd05f25509a98223b69594e4d0e5c27ce01111f80dd2df8ffd5f1af75bd6d663f55c4186ef773da2168ac1c',\n      signedByDelegate: false,\n      signatureDeadline: 1674736509,\n      typedData: {\n        types: {\n          PostWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'contentURI',\n              type: 'string',\n            },\n            {\n              name: 'collectModule',\n              type: 'address',\n            },\n            {\n              name: 'collectModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        value: {\n          profileId: '0x18',\n          contentURI: 'ar://NKrOBI6zMU4mnptAGYvirARSvBAU-nkCITQ5-LZkEco',\n          collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n          collectModuleInitData: '0x',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          referenceModuleInitData: '0x',\n          nonce: 243,\n          deadline: 1674736509,\n        },\n      },\n      blockHash: '0x43f670549e740c8b2b7b56967b8a24a546b734c83e05ba20a515faddddc7c345',\n      blockNumber: 31429670,\n      blockTimestamp: 1674736509,\n    },\n    pointer: null,\n  },\n  publicationId: '0x18-0x3a-DA-951a2a24',\n  event: {\n    profileId: '0x18',\n    pubId: '0x3a',\n    contentURI: 'ar://NKrOBI6zMU4mnptAGYvirARSvBAU-nkCITQ5-LZkEco',\n    collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n    collectModuleReturnData: '0x',\n    referenceModule: '0x0000000000000000000000000000000000000000',\n    referenceModuleReturnData: '0x',\n    timestamp: 1674736509,\n  }\n}\n```\n\n### Post v2 example\n\n```js\n{\n  signature: '0x255da3b710d96789ab4873919739fca75dbf439df42b6f4d46d25629910f6b561b3aba11533a46dc09cb577c65ecf1ac7d11cb7b5c12b002a2234ff0f7de01561b',\n  dataAvailabilityId: '43a4436d-a14f-4121-97ad-ba9f7ee43ae0',\n  type: 'POST_CREATED',\n  timestampProofs: {\n      type: 'BUNDLR',\n      hashPrefix: '1',\n      response: {\n        id: 'PIdmqKf3QKmFHkyATwEUSavyInNCFdZKL7RARgGRQoI',\n        timestamp: 1702891714460,\n        version: '1.0.0',\n        public: 'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n        signature: 'Ab2bHqzPmgaVPZumC1la7N7xyH6KHYh017afzJn-dUDvVE-VenvpzBTO199BslAb0-hXj7TSRHy0GXW34qzxlich9pxqdQhgwjAy_whKPkTt2ZU7i89-9sm7FOEirkxYvpqo8c2rPHKmF0nkM1aMEKbYpXAxWJp-CCdMdBQDWzKrh2fhl9BNL8wTvPjDw5QHH-kCOXrnrptbO1KZrV3n30utnjMPhyoa2_Kgr96FgrFLvNfDNBoHoOcr_Nv4VHxPjkR3Ph70dFe_U4nzdSllJgyA12EgrAh2XIqZ4qnDBRxw5CBvY5XYoK0zvj-ikTotrFxUoazva6MoBJxlLEgpKbyF-ztEcvx8xQvFEqhGtJcQVmGvpR5RlGZdliozwt2N1VX9y8-NdGDPzfyhu9c_VBgzJQAThBvVDTNUcmHTygLipkc2YjYyD0I_etXRFhPtJqgY5Z9DSohAydqZ3IUSr-QoefLtypWe_DiJJleFGRliSpU5kgUqOaIH6D82iZctmYBS7oVsPkBp-37qjBHXB5u7t6gfpA9eWyJ-UCOoGpgy-I9YqhitSosMa24JgmTDIwx8Ab9AGhJcge-qpaXvNQbEwfMEHd5awMY4BRCLKm8kH8HBsHyWZllTrqLZzP25Lly-B3mM3NodybMTAXRyeca9uWqmlgZjrhE7cvy79Ns',\n        deadlineHeight: 1328843,\n        block: 1328843,\n        validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n        signature: '0xf4c37eda3f8ea409b6fa51f53ff2db1fe778e9000e2ebc9e0bb9a5426f6617671194e5d4069c6c868dea9c6826173184b56d4730bd18dbbf3f7037f9e2dbbfc31c',\n        signedByDelegate: true,\n        signatureDeadline: 1702891712,\n        typedData: {\n        types: {\n          Post: [{\n            type: 'uint256',\n            name: 'profileId',\n          },\n            {\n              type: 'string',\n              name: 'contentURI',\n            },\n            {\n              type: 'address[]',\n              name: 'actionModules',\n            },\n            {\n              type: 'bytes[]',\n              name: 'actionModulesInitDatas',\n            },\n            {\n              type: 'address',\n              name: 'referenceModule',\n            },\n            {\n              type: 'bytes',\n              name: 'referenceModuleInitData',\n            },\n            {\n              type: 'uint256',\n              name: 'nonce',\n            },\n            {\n              type: 'uint256',\n              name: 'deadline',\n            },\n          ],\n        },\n        domain: {\n            name: 'Lens Protocol Profiles',\n            version: '2',\n            chainId: 137,\n            verifyingContract: '0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d',\n        },\n        value: {\n            profileId: '0x010ba2',\n            contentURI: 'https://data.lens.phaver.com/api/lens/posts/09e32dc3-280c-41b6-84af-adfe00b1518b',\n            actionModules: [],\n            actionModulesInitDatas: [],\n            referenceModule: '0x0000000000000000000000000000000000000000',\n            referenceModuleInitData: '0x',\n            nonce: 0,\n            deadline: 1702891712,\n        },\n      },\n      blockHash: '0x345881b9a7e9450b0d7a6a393f7d0eeaab76c638ddf1b73911bd895d904acf0f',\n      blockNumber: 51266720,\n      blockTimestamp: 1702891712,\n    },\n    pointer: null,\n  },\n  publicationId: '0x010ba2-0x0753-DA-43a4436d',\n  event: {\n    postParams: {\n        profileId: '0x010ba2',\n        contentURI: 'https://data.lens.phaver.com/api/lens/posts/09e32dc3-280c-41b6-84af-adfe00b1518b',\n        actionModules: [],\n        actionModulesInitDatas: [],\n        referenceModule: '0x0000000000000000000000000000000000000000',\n        referenceModuleInitData: '0x',\n    },\n    pubId: '0x0753',\n    actionModulesInitReturnDatas: [],\n    referenceModuleInitReturnData: '0x',\n    transactionExecutor: '0xbb8d9991542baC0c77bF8f8E650CAb7B873c3C6D',\n    timestamp: 1702891712,\n  }\n}\n```\n\n### Comment v1 example\n\n```js\n{\n  signature:\n    '0xcd9824d89bd3b237ed1230cf914630d756cae83904d835a1e85d37c11dbfab5e42c1f02042469ab29a3ccbd428c9a64576ad77f5876130b9c2bd49e0a83e9b7c1c',\n  dataAvailabilityId: '9a0b1d2b-e36e-48fc-87b4-b5f3f509b494',\n  type: MomokaActionTypes.COMMENT_CREATED,\n  timestampProofs: {\n    type: MomokaProvider.BUNDLR,\n    hashPrefix: '1',\n    response: {\n      id: 'xtVsUj5j1T4T86IQlJk2u-KubGD5oKIXOJQlU3KyGR0',\n      timestamp: 1674747795383,\n      version: '1.0.0',\n      public:\n        'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n      signature:\n        'TZh1F7z14pbuHq7IBlHqnhT4PXEa2dQngiL-iHEXot3-w_ScVLyN9naCeuHvAP4mialS62YPucToy4o1UQlMEtTYS2i6C0rPap32xGi2yDA6AtzURf-xELI33em-mr9QIEuOph34t0yRLn3_Bl0n-AV4jyjVSgHdYjUT0vNZx3TbRkBi_v0PgJHDYkyezP_NrZgTomEe_VZmBgozc0J9zzK6atbIdsPnHYDbY3qzTujJEwogVQa311lNZvVe2ND6MR_0EUyVVW0esin6dyYEIPPCrjlFwMMgaoW4vBbGd1d11cRGopYgNvcX_0EuwAWYGwi8XW_GNGyrk4Df14VnOXAuP4NKd5oia820Be1vqwuAs3ubWX0OQ7CttOgohO9ns7CjYg9DVIwY5-AuJd2wAK6eI09fot-lTNVwtMVBvyxQ4GWaYspMcqkpysOY-5ow0wFp7K4Ad1FI4NO71cbEZQWD8ou08_A5Gd2a6qZF2fb7IJKka0aim26N858faf1nqViZfL-aym-AW60ydNav8inrTxVTMXml61WeG4KwlQXDrdoWkEquLB-1mJ-_519ozgy0QjSbyctp4LjpDpdp-yiJvzfweMFVRIKxarVB9Vvc0NFhyllE8sZud8zLBZ7wo7GG_1wijCJaICo-iD_FK97ZegnhotGLzeDC-KqY2vQ',\n      deadlineHeight: 1106619,\n      block: 1106619,\n      validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n      signature:\n        '0x5156c7e636be61a305373df811d8444b7715448e2bde3fe69d388f301270d83d72796c5ef58283c1a9d32b37033a6b567a32addb78aedef0957fbf56956cd2351b',\n      signedByDelegate: false,\n      signatureDeadline: 1674747793,\n      typedData: {\n        types: {\n          CommentWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'contentURI',\n              type: 'string',\n            },\n            {\n              name: 'profileIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'pubIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'referenceModuleData',\n              type: 'bytes',\n            },\n            {\n              name: 'collectModule',\n              type: 'address',\n            },\n            {\n              name: 'collectModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        value: {\n          profileId: '0x18',\n          profileIdPointed: '0x18',\n          pubIdPointed: '0x3a',\n          contentURI: 'ar://5JNO_BIyW7sD8crn1PPt3SrCZUKF9t-f8Rs13Zh1w1Q',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n          collectModuleInitData: '0x',\n          referenceModuleInitData: '0x',\n          referenceModuleData: '0x',\n          nonce: 243,\n          deadline: 1674747793,\n        },\n      },\n      blockHash: '0x11b2e5b1b7fa87c3a30d10d6f0416f5cb540c30ac7ae4b1be5058d9b5031e172',\n      blockNumber: 31434975,\n      blockTimestamp: 1674747793,\n    },\n    pointer: {\n      location: 'ar://TEoFkgD0m-LLQkfViuCTKfCLK_xpSxzPUNoMjBLnvlI',\n      type: DAPublicationPointerType.ON_DA,\n    },\n  },\n  publicationId: '0x18-0x3a-DA-9a0b1d2b',\n  event: {\n    profileId: '0x18',\n    pubId: '0x3a',\n    contentURI: 'ar://5JNO_BIyW7sD8crn1PPt3SrCZUKF9t-f8Rs13Zh1w1Q',\n    profileIdPointed: '0x18',\n    pubIdPointed: '0x3a',\n    referenceModuleData: '0x',\n    collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n    collectModuleReturnData: '0x',\n    referenceModule: '0x0000000000000000000000000000000000000000',\n    referenceModuleReturnData: '0x',\n    timestamp: 1674747793,\n  }\n}\n```\n\n### Comment v2 example\n\n```js\n{\n    signature: '0x6e0e55679ca0b42dcb8fd82f8c5837088785c41de23ee3932577f5322741ebe72bc7af941aa775c86b1738ba36c904a4768806794443d9900c5274c7d156ac3c1c',\n    dataAvailabilityId: '78851796-9590-4822-97de-ceb265510b5d',\n    type: 'COMMENT_CREATED',\n    timestampProofs: {\n        type: 'BUNDLR',\n        hashPrefix: '1',\n        response: {\n            id: 'RQ8mCXnYCluZIop4Lw5oEkEGiZo3QnxJX0vJtHY0pN8',\n            timestamp: 1702891713472,\n            version: '1.0.0',\n            public: 'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n            signature: 'U-EnE5GqBWl9FRhckT8NO5ESjoSoGPVyysZMEKB6cciWc-3YsOUm1syC-JjKNZHqk5FhlDOChs6vpzBWFksxTxXL_dGeifWN1Vd3Adc-lPueHWsY4wi00AZPb9fkHZAJ1PTZyzNvO0sCtfIUF1KYsCU75Vq_-Eul0lfCgaHjbO91EYFeGiJmBgtqcFmCaABEcIPCgqo3B8FnzXei5FopqXaa8yEDe6mcA146SatnNRX5GB0QH7g7PFEkExizcOcKc9ELSuja84np41ouEyoInhTOVHipcuSASRTf20NgUHtZwImQF33YcjXpX9PPFVecxdslrqA83O_K0R6Y-J0mZb0ZRMdQ85DC6febn6LaMGn1-OagAisuALFrGyGcdH-1gagdsGQ9K86vE0T8n0PZapqB81qDSz7sPpGik-uqdXXJT1fGXYJzHy7QcnzLkt8RAADEmwaJfdzxECr-OpqkRxLovVuDB6C29ZrsVaXQ4iDx8FKbLjUbHrYFsOnRTLKi4b3Q-ImjvVNKm2Jur-cx3NSsC2zhdH-MWiR8D7bfVALNayU6QC0IeXGo_S0di70AqaFsjGwjv9hFIRhzxNnhR2VBGWCIuh9cD_icfabB1c6xKDaYLM4gim6q9foksHQ4bz7CEya40yKq8K2O18pA-MwLSDAzCNjj96FF-NBqeuo',\n            deadlineHeight: 1328843,\n            block: 1328843,\n            validatorSignatures: [],\n        },\n    },\n    chainProofs: {\n        thisPublication: {\n            signature: '0x5965cb73b4437e31820fc3e62fadc96b0fe885da77131b14e9d5265b1aee9cbf128dd60e36e9798640ee81c04d908d03b0d11d2114687b545bc778adba05ca1f1b',\n            signedByDelegate: true,\n            signatureDeadline: 1702891712,\n            typedData: {\n                types: {\n                    Comment: [{\n                            type: 'uint256',\n                            name: 'profileId',\n                        },\n                        {\n                            type: 'string',\n                            name: 'contentURI',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'pointedProfileId',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'pointedPubId',\n                        },\n                        {\n                            type: 'uint256[]',\n                            name: 'referrerProfileIds',\n                        },\n                        {\n                            type: 'uint256[]',\n                            name: 'referrerPubIds',\n                        },\n                        {\n                            type: 'bytes',\n                            name: 'referenceModuleData',\n                        },\n                        {\n                            type: 'address[]',\n                            name: 'actionModules',\n                        },\n                        {\n                            type: 'bytes[]',\n                            name: 'actionModulesInitDatas',\n                        },\n                        {\n                            type: 'address',\n                            name: 'referenceModule',\n                        },\n                        {\n                            type: 'bytes',\n                            name: 'referenceModuleInitData',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'nonce',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'deadline',\n                        },\n                    ],\n                },\n                domain: {\n                    name: 'Lens Protocol Profiles',\n                    version: '2',\n                    chainId: 137,\n                    verifyingContract: '0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d',\n                },\n                value: {\n                    actionModules: [],\n                    actionModulesInitDatas: [],\n                    contentURI: 'https://data.lens.phaver.com/api/lens/comments/28a020f6-d3ed-40e9-86ae-9fd65e0ff762',\n                    deadline: 1702891712,\n                    nonce: 0,\n                    pointedProfileId: '0x01e949',\n                    pointedPubId: '0x02',\n                    profileId: '0x8780',\n                    referenceModule: '0x0000000000000000000000000000000000000000',\n                    referenceModuleData: '0x',\n                    referenceModuleInitData: '0x',\n                    referrerProfileIds: [],\n                    referrerPubIds: [],\n                },\n            },\n            blockHash: '0x345881b9a7e9450b0d7a6a393f7d0eeaab76c638ddf1b73911bd895d904acf0f',\n            blockNumber: 51266720,\n            blockTimestamp: 1702891712,\n        },\n        pointer: {\n            location: 'ar://KsFdzdb71cxbBCvO_yUpTAZylNjdjVXXHTl1RU0Kv_k',\n            type: 'ON_DA',\n        },\n    },\n    publicationId: '0x8780-0x0187-DA-78851796',\n    event: {\n        commentParams: {\n            profileId: '0x8780',\n            contentURI: 'https://data.lens.phaver.com/api/lens/comments/28a020f6-d3ed-40e9-86ae-9fd65e0ff762',\n            actionModules: [],\n            actionModulesInitDatas: [],\n            referenceModule: '0x0000000000000000000000000000000000000000',\n            referenceModuleInitData: '0x',\n            referenceModuleData: '0x',\n            referrerProfileIds: [],\n            referrerPubIds: [],\n            pointedProfileId: '0x01e949',\n            pointedPubId: '0x02',\n        },\n        pubId: '0x0187',\n        actionModulesInitReturnDatas: [],\n        referenceModuleReturnData: '0x',\n        referenceModuleInitReturnData: '0x',\n        transactionExecutor: '0x6FB0974523bE06231516Ee7CCEdad7e1897e8942',\n        timestamp: 1702891712,\n    }\n}\n```\n\n### Mirror v1 example\n\n```js\n{\n  signature:\n    '0x1683ef107f09a291ebbe8f4bfc4f628ff9be10f661d0d18048c31a8b1ca981d948ef12c591e5d762e952bc287e57838b031a6451f2b8a58cfc5cedb565c742661b',\n  dataAvailabilityId: '538ca9c4-682b-41d2-9b8a-52ede43728d7',\n  type: MomokaActionTypes.MIRROR_CREATED,\n  timestampProofs: {\n    type: MomokaProvider.BUNDLR,\n    hashPrefix: '1',\n    response: {\n      id: 'zdkCXuVzawg3KipWCRVK2fo-yIUoj5IMuIYyFPGA55o',\n      timestamp: 1674748125246,\n      version: '1.0.0',\n      public:\n        'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n      signature:\n        'IJjhzO0D4ioq9Gc0mghnxvOIkrZdmrqkc_UpMkL9R-qulzvkZ_LY4QRQxP-rNAm-ZIoN3Jep9zefjTaRRvU6mhc6hKZaMWC4XvWW_IXl5TZH1eOfq0JENjoRoZ75IdwicJXtc9c7obeNs84hXqlNHJXUoQfC2mEjkqiRpK_Vz43Hxn-3ZkrNvNEM1cpbl5hJU3UP0iCQnJQPiTgiojnhTBgRoIEpLQBFdoF1IRXUH4J4TBCMoX5MzG5PUj_FJkJiYX_SM0iaiDi0y-6-IsvOu1o32UWVgmDa-PbTrd6kGuDdd3Ys4HHyjGbS4NGkbu-coMW7RdkCegowgrXvzDoVxG0pVKoMK7ndOfZJJlud3jonqcDDI0vESSVdt_DDMOjkqdHiyWdVWcDlS0TnToIdwuOgaHDgpoqFjPUd5GwE40QFix6QflbxfcFqleru9eDY4_hufxMYEWK3DiSN6QIe6jQg6-9ZLFvD4Chr_bxL48UkfwDx-Y7EZo5tb6uzwzEqAfXEb5ITyzVrEgo1sXEDKKkkNQ7C5Hq2mryWKRXHUtXkKErI1P_bNRp2GXumO30uwZfpsMcAtFPCsPMnm1j4aqhFjcpVk9HpFPa6DcCuX6U8T3MODbJbNPxFc_Pdt5wcLo6EcLEnnQTIvQEIj_aQvh__rh79d6XHckI1TL-9gAM',\n      deadlineHeight: 1106621,\n      block: 1106621,\n      validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n      signature:\n        '0x59cb0d34ef20e93e4073cadec0d05eb8ef9a6af4b55d7ddea099666f83509d193e554c4149856ddb36ac3a4601c7f4e12fc413e016b6d4b314846eb3222b2e9b1b',\n      signedByDelegate: false,\n      signatureDeadline: 1674748123,\n      typedData: {\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        types: {\n          MirrorWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'profileIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'pubIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'referenceModuleData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        value: {\n          profileId: '0x18',\n          profileIdPointed: '0x18',\n          pubIdPointed: '0x3a',\n          referenceModuleData: '0x',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          referenceModuleInitData: '0x',\n          deadline: 1674748123,\n          nonce: 243,\n        },\n      },\n      blockHash: '0x0fb258841acaf93b998028bfc7296b840a80cdc76ffd999d5101bc72cf2daf78',\n      blockNumber: 31435129,\n      blockTimestamp: 1674748123,\n    },\n    pointer: {\n      location: 'ar://ff9CtLecXt1HBFBR-SoRz8tLjPjBo8gxbmy7kmFpJl4',\n      type: DAPublicationPointerType.ON_DA,\n    },\n  },\n  publicationId: '0x18-0x3a-DA-538ca9c4',\n  event: {\n    profileId: '0x18',\n    pubId: '0x3a',\n    profileIdPointed: '0x18',\n    pubIdPointed: '0x3a',\n    referenceModuleData: '0x',\n    referenceModule: '0x0000000000000000000000000000000000000000',\n    referenceModuleReturnData: '0x',\n    timestamp: 1674748123,\n  }\n}\n```\n\n### Mirror v2 example\n\n```js\n{\n    signature: '0x4c0a44fe4b176994c8f08b1140925dc798d964924d8ef0ee2ef106ee7becfc16106a6291b2a8c5348df434a61f776c7426cce72827a997db2cad6e689f889af81b',\n    dataAvailabilityId: '07e11c4b-f941-41fa-886e-0ce80abe5ee6',\n    type: 'MIRROR_CREATED',\n    timestampProofs: {\n        type: 'BUNDLR',\n        hashPrefix: '1',\n        response: {\n            id: 'z6xdw5Z6etMF11TubShsFlcY-sVgyJDFwfnka7aZdwo',\n            timestamp: 1702891817115,\n            version: '1.0.0',\n            public: 'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n            signature: 'oaiXw1bYhNKnc7yDocvm6C0MCesIOLKDpBwxgDqvoLZsqA9JXuk1XZ44iQjvFYzGwAhkJWkwq1TV4NhKRaeZV3NK_IA54DSWikze1PiJ2ag7O9fvyO_NIdZNeFOoQLuKuh1ZxueaccttO0KGCxXgWBY4YGW1i-UttXDmVr9RxaQQJ_ul-vFSdjnACm8S8OzxXrc5kHRujxjnzFpcQtOD4YgWvKJ6kRgyxQIxL62bDc-Ubjwr-3Upz0wEvI2nfPlvDpZfpJVaLuSD_qd7k26ZgQjMfWKhXXVyyuszS8MElWB42YkOZQnJKPeMEdAQPrpbz3wjqNOv3uP_Y57RAIFYw1ZQIQz0cNw_L_apCuFJS5Hbv7slMkyC-6AOnZVGVsbjv0Wsk7KPWj3-UMACndw25ta2nOWewt1ubHRqvY9pWpTh0O6Y5oeCxy2H4sDw8QLMlkPC6tU4q5L_TjAkBp-SXt6wx6M8C1Ra9hLe0uN4xPG8rZdsSQEm5ueyHLV6tLiIEqsq2Vj5chJuycLHRqIqPEkeptKA4aR-JHmLn_4d2qLniDMun1n_oTjVBgypHOYvBAuPWFN4CrBHu6V8e6rf1UqSS_UB720z2NQhlZxUwbf5jjLzeAgap2v-Il9AMhH7Gleh3cQrrmM1NLr0yihR7PiCKROTFK4cqldDyi7r7Mk',\n            deadlineHeight: 1328843,\n            block: 1328843,\n            validatorSignatures: [],\n        },\n    },\n    chainProofs: {\n        thisPublication: {\n            signature: '0xc83854f2711e805a6cd761a50436a45d2ecde7ae37d4e96dd624bd44cb4daf434c7456cb90f2a5be5913f68cd9b40c3997f5aa1c676b903a3ea7c2590d24852a1b',\n            signedByDelegate: true,\n            signatureDeadline: 1702891816,\n            typedData: {\n                types: {\n                    Mirror: [{\n                            type: 'uint256',\n                            name: 'profileId',\n                        },\n                        {\n                            type: 'string',\n                            name: 'metadataURI',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'pointedProfileId',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'pointedPubId',\n                        },\n                        {\n                            type: 'uint256[]',\n                            name: 'referrerProfileIds',\n                        },\n                        {\n                            type: 'uint256[]',\n                            name: 'referrerPubIds',\n                        },\n                        {\n                            type: 'bytes',\n                            name: 'referenceModuleData',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'nonce',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'deadline',\n                        },\n                    ],\n                },\n                domain: {\n                    name: 'Lens Protocol Profiles',\n                    version: '2',\n                    chainId: 137,\n                    verifyingContract: '0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d',\n                },\n                value: {\n                    deadline: 1702891816,\n                    metadataURI: '',\n                    nonce: 0,\n                    pointedProfileId: '0x01dd85',\n                    pointedPubId: '0x010d',\n                    profileId: '0x73b1',\n                    referenceModuleData: '0x',\n                    referrerProfileIds: [],\n                    referrerPubIds: [],\n                },\n            },\n            blockHash: '0xf55674ae4a179088bcbe0aa7ac340a42098fc6ed8a941d38294585408b062c69',\n            blockNumber: 51266755,\n            blockTimestamp: 1702891816,\n        },\n        pointer: {\n            location: 'ar://FnKDUBDZTGiwDR3X8isbLxMyII93jDSbLDXdiG1jElU',\n            type: 'ON_DA',\n        },\n    },\n    publicationId: '0x73b1-0x44d6-DA-07e11c4b',\n    event: {\n        mirrorParams: {\n            profileId: '0x73b1',\n            metadataURI: '',\n            referenceModuleData: '0x',\n            referrerProfileIds: [],\n            referrerPubIds: [],\n            pointedProfileId: '0x01dd85',\n            pointedPubId: '0x010d',\n        },\n        pubId: '0x44d6',\n        referenceModuleReturnData: '0x',\n        transactionExecutor: '0x3D5e9077ef8F9C6B0e10D6c62C1A022a49675Cc3',\n        timestamp: 1702891816,\n    },\n}\n```\n\n### Quote v1 metadata\n\nQuote was not supported in v1.\n\n### Quote v2 metadata\n\n```js\n{\n    signature: '0x1509b8efdaa96410fc975eaaa0f2f2cf587440c5fe6c08212d7ee2f3812adab018be0d29f4913f21f797b58b25d98e5c0b2f7aa517bade28de07c1a119a361dc1c',\n    dataAvailabilityId: 'ff75b024-8d38-4265-bfb6-75de3594696c',\n    type: 'QUOTE_CREATED',\n    timestampProofs: {\n        type: 'BUNDLR',\n        hashPrefix: '1',\n        response: {\n            id: '_s1fhwtNOc0rHtXuW5H1gybe3yKveNcDzDSqvRyHF2s',\n            timestamp: 1702892441416,\n            version: '1.0.0',\n            public: 'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n            signature: 'INzP87eVTYwFRZ7ujA2P9bhw87oA9TzDdOgofAxT1Nn1pQkcRlgEgNT36o0HzGCPhOszxJb74NZwNS-gFA7pKxf0DwJsPF-a3uL_hodhQXoJTsazxdl8sE5Y5bIa5R4jm2AvU_g9YDAnL9v4y7dYADhn997ozEniEt5ChVa4bxvMFQ5-cFx4tLDHQniSf-VNrUPoAFrVintbyoPCVDj_djDU2rOcfE86WNKiNg71pTBLGrJmF5xRVAbSKCDTlwzgJeIqID-IrhhcSHC2TdUXG2uBXhkt0GDsKJISuzeuFlH-atfEqqLyJcbkxWixuvJ5EpwzvNDnWq7-lFCi-yM_UbxRwwJqWgZK9abxk0Fa0LsnFUgOAkhsKqxKVzyjUuaXvryZHP61gUo6rtc6NfaKR48FTLFPNmOdzSb0gzCFRiym78S1cdL2LdmCBYNv3wft4QQ2d3RMTGie4QhC-hdsjMDqZlWIAVmTcR5TVEacW7pcC4Wrfa-dNHxIGT_bJwPeZIEXy-WUdCDMlVO4D0hh1SDvWkzFPI_0gDbxMhTPMUaf_EVSDZ7X7m3MT5gCZAzuL1Z-G9xwzupE-II8eTD_15xwmOEodpjgs_aVDsGaI1PFGgsLcOpN4xjOrQQgVOB4yFlTZvSE1Y0H4x8S4IMIdTYfMmm_Vlb0HDnX6geFHuk',\n            deadlineHeight: 1328851,\n            block: 1328851,\n            validatorSignatures: [],\n        },\n    },\n    chainProofs: {\n        thisPublication: {\n            signature: '0x56abf2084499f2cbca722894dabb3a1664f5fe4a2cabdfd2dc6a266177a3d3731acaa216869d61a1582db4165a76658af6eefce04d82bb6b2eef607bf11f4da91c',\n            signedByDelegate: true,\n            signatureDeadline: 1702892439,\n            typedData: {\n                types: {\n                    Quote: [{\n                            type: 'uint256',\n                            name: 'profileId',\n                        },\n                        {\n                            type: 'string',\n                            name: 'contentURI',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'pointedProfileId',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'pointedPubId',\n                        },\n                        {\n                            type: 'uint256[]',\n                            name: 'referrerProfileIds',\n                        },\n                        {\n                            type: 'uint256[]',\n                            name: 'referrerPubIds',\n                        },\n                        {\n                            type: 'bytes',\n                            name: 'referenceModuleData',\n                        },\n                        {\n                            type: 'address[]',\n                            name: 'actionModules',\n                        },\n                        {\n                            type: 'bytes[]',\n                            name: 'actionModulesInitDatas',\n                        },\n                        {\n                            type: 'address',\n                            name: 'referenceModule',\n                        },\n                        {\n                            type: 'bytes',\n                            name: 'referenceModuleInitData',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'nonce',\n                        },\n                        {\n                            type: 'uint256',\n                            name: 'deadline',\n                        },\n                    ],\n                },\n                domain: {\n                    name: 'Lens Protocol Profiles',\n                    version: '2',\n                    chainId: 137,\n                    verifyingContract: '0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d',\n                },\n                value: {\n                    actionModules: [],\n                    actionModulesInitDatas: [],\n                    contentURI: 'ar://GbtyAwAME-RGiujxS3NLVhNQAiCbcSlZ26coVU4Kwqc',\n                    deadline: 1702892439,\n                    nonce: 0,\n                    pointedProfileId: '0x0155a4',\n                    pointedPubId: '0x0b24',\n                    profileId: '0x0155a4',\n                    referenceModule: '0x0000000000000000000000000000000000000000',\n                    referenceModuleData: '0x',\n                    referenceModuleInitData: '0x',\n                    referrerProfileIds: [],\n                    referrerPubIds: [],\n                },\n            },\n            blockHash: '0x31934ea8a4b44ab9eea34041a5d96eae9bb0dc2c41c6686afe0a8670701ac286',\n            blockNumber: 51267046,\n            blockTimestamp: 1702892439,\n        },\n        pointer: {\n            location: 'ar://H5mFMCkjaBMkoQTo6QNd0JYB5jDdxpOuHrNXkfoaaxo',\n            type: 'ON_DA',\n        },\n    },\n    publicationId: '0x0155a4-0x0b24-DA-ff75b024',\n    event: {\n        quoteParams: {\n            profileId: '0x0155a4',\n            contentURI: 'ar://GbtyAwAME-RGiujxS3NLVhNQAiCbcSlZ26coVU4Kwqc',\n            actionModules: [],\n            actionModulesInitDatas: [],\n            referenceModule: '0x0000000000000000000000000000000000000000',\n            referenceModuleInitData: '0x',\n            referenceModuleData: '0x',\n            referrerProfileIds: [],\n            referrerPubIds: [],\n            pointedProfileId: '0x0155a4',\n            pointedPubId: '0x0b24',\n        },\n        pubId: '0x0b24',\n        actionModulesInitReturnDatas: [],\n        referenceModuleReturnData: '0x',\n        referenceModuleInitReturnData: '0x',\n        transactionExecutor: '0x8D1a7BeEfCCCbaB825AB3B024A2aBf408e776100',\n        timestamp: 1702892439,\n    },\n}\n```\n\n### Metadata breakdown\n\nThis will explain in json schema terms what a DA publication metadata holds.\n\n#### POST_CREATED\n\nCan hold either v1 or v2 post.\n\n##### V1 metadata\n\n```json\n{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"title\": \"The data availability layer schema\",\n  \"description\": \"The data availability layer schema\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"dataAvailabilityId\": {\n      \"description\": \"The id of the publication on the data availability layer; it is just a GUID\",\n      \"type\": \"guid\"\n    },\n    \"signature\": {\n      \"description\": \"The signature of the entire payload signed by the submitter\",\n      \"type\": \"string\"\n    },\n    \"type\": {\n      \"description\": \"`POST_CREATED`, `COMMENT_CREATED`, `MIRROR_CREATED` the DA action type which has been submitted\",\n      \"type\": \"POST_CREATED\"\n    },\n    \"timestampProofs\": {\n      \"description\": \"Details for the timestamp proofs\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"type\": {\n          \"description\": \"`BUNDLR` - who has supplied us with the timestamp proofs\",\n          \"type\": \"string\"\n        },\n        \"hashPrefix\": {\n          \"description\": \"The timestamp proof hash prefix\",\n          \"type\": \"number\"\n        },\n        \"response\": {\n          \"description\": \"The response from the timestamp proof provider\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"id\": {\n              \"description\": \"The id of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"timestamp\": {\n              \"description\": \"The timestamp date in milliseconds\",\n              \"type\": \"number\"\n            },\n            \"version\": {\n              \"description\": \"The version of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"public\": {\n              \"description\": \"The public key used sign for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"signature\": {\n              \"description\": \"The signature for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"deadlineHeight\": {\n              \"description\": \"Internal deadline height for the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"block\": {\n              \"description\": \"Internal block for the timestamp proof (this is not an evm block)\",\n              \"type\": \"number\"\n            },\n            \"validatorSignatures\": {\n              \"description\": \"Internal validator signatures for the timestamp proof (this will always be an empty array for now until Bundlr is decentralised)\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          },\n          \"required\": [\n            \"id\",\n            \"timestamp\",\n            \"version\",\n            \"public\",\n            \"signature\",\n            \"deadlineHeight\",\n            \"block\",\n            \"validatorSignatures\"\n          ]\n        }\n      },\n      \"required\": [\"type\", \"hashPrefix\", \"response\"]\n    },\n    \"chainProofs\": {\n      \"description\": \"The proofs\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"thisPublication\": {\n          \"description\": \"The publication being submitted\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"signature\": {\n              \"description\": \"The transaction signature\",\n              \"type\": \"string\"\n            },\n            \"signedByDelegate\": {\n              \"description\": \"If the signature was signed by a delegate/dispatcher\",\n              \"type\": \"boolean\"\n            },\n            \"signatureDeadline\": {\n              \"description\": \"The deadline of the signature in unix form\",\n              \"type\": \"number\"\n            },\n            \"typedData\": {\n              \"description\": \"The typed data of the transaction; this uses the signed typed data spec\",\n              \"type\": \"object\",\n              \"properties\": {\n                \"types\": {\n                  \"description\": \"The types of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"PostWithSig\": {\n                      \"description\": \"The properties of the typed data\",\n                      \"type\": \"array\",\n                      \"items\": {\n                        \"description\": \"The name and type of the property\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                          \"name\": {\n                            \"description\": \"The name of typed data\",\n                            \"type\": \"string\"\n                          },\n                          \"type\": {\n                            \"description\": \"The type typed data\",\n                            \"type\": \"string\"\n                          }\n                        },\n                        \"required\": [\"name\", \"type\"]\n                      }\n                    }\n                  },\n                  \"required\": [\"types\"]\n                },\n                \"domain\": {\n                  \"description\": \"The domain of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"name\": {\n                      \"description\": \"The name of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"version\": {\n                      \"description\": \"The version of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"chainId\": {\n                      \"description\": \"The chain id of the signed typed data\",\n                      \"type\": \"number\"\n                    },\n                    \"verifyingContract\": {\n                      \"description\": \"The verifying contract\",\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"required\": [\n                    \"name\",\n                    \"version\",\n                    \"chainId\",\n                    \"verifyingContract\"\n                  ]\n                },\n                \"value\": {\n                  \"description\": \"The value of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"profileId\": {\n                      \"description\": \"The profile id doing the publication\",\n                      \"type\": \"string\"\n                    },\n                    \"contentURI\": {\n                      \"description\": \"The content metadata URI\",\n                      \"type\": \"string\"\n                    },\n                    \"collectModule\": {\n                      \"description\": \"The collect module address - will always be a revert collect module at the moment\",\n                      \"type\": \"string\"\n                    },\n                    \"collectModuleInitData\": {\n                      \"description\": \"The collect module init data - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModule\": {\n                      \"description\": \"The reference module will always be address(0) for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModuleInitData\": {\n                      \"description\": \"The reference module init data will - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"nonce\": {\n                      \"description\": \"The signature nonce\",\n                      \"type\": \"number\"\n                    },\n                    \"deadline\": {\n                      \"description\": \"The signature deadline in unix form\",\n                      \"type\": \"number\"\n                    }\n                  },\n                  \"required\": [\n                    \"profileId\",\n                    \"contentURI\",\n                    \"collectModule\",\n                    \"collectModuleInitData\",\n                    \"referenceModule\",\n                    \"referenceModuleInitData\",\n                    \"nonce\",\n                    \"deadline\"\n                  ]\n                }\n              },\n              \"required\": [\"types\", \"domain\", \"value\"]\n            },\n            \"blockHash\": {\n              \"description\": \"The block hash the submitter simulated this transaction on\",\n              \"type\": \"string\"\n            },\n            \"blockNumber\": {\n              \"description\": \"The block number the submitter simulated this transaction on\",\n              \"type\": \"number\"\n            },\n            \"blockTimestamp\": {\n              \"description\": \"The block unix timestamp of the simulated transaction\",\n              \"type\": \"number\"\n            }\n          },\n          \"required\": [\n            \"signature\",\n            \"signedByDelegate\",\n            \"signatureDeadline\",\n            \"typedData\",\n            \"blockHash\",\n            \"blockNumber\",\n            \"blockTimestamp\"\n          ]\n        }\n      },\n      \"required\": [\"thisPublication\"]\n    },\n    \"publicationId\": {\n      \"description\": \"The id of the publication, which is built up of the profileId + pubId + `DA` + first eight chars of the dataAvailabilityId (so it will always be unique)\",\n      \"type\": \"string\"\n    },\n    \"event\": {\n      \"description\": \"This is trying to shape what you would get within an `EVM` event so you can easily parse it and understand it. This will always be identical to the EVM event data structure.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"profileId\": {\n          \"description\": \"The profileId which did the publication\",\n          \"type\": \"string\"\n        },\n        \"pubId\": {\n          \"description\": \"The pubId for the publication\",\n          \"type\": \"string\"\n        },\n        \"contentURI\": {\n          \"description\": \"The contentURI aka metadata for the publication\",\n          \"type\": \"string\"\n        },\n        \"collectModule\": {\n          \"description\": \"The collect module, for now it will always be revert module\",\n          \"type\": \"string\"\n        },\n        \"collectModuleReturnData\": {\n          \"description\": \"The collect module return data, will always for now be empty byte\",\n          \"type\": \"string\"\n        },\n        \"referenceModule\": {\n          \"description\": \"The reference module, will always be address(0) for now\",\n          \"type\": \"string\"\n        },\n        \"referenceModuleReturnData\": {\n          \"description\": \"The reference module return data, will always for now be empty byte\",\n          \"type\": \"string\"\n        },\n        \"timestamp\": {\n          \"description\": \"The timestamp date in milliseconds\",\n          \"type\": \"number\"\n        }\n      },\n      \"required\": [\n        \"profileId\",\n        \"pubId\",\n        \"contentURI\",\n        \"collectModule\",\n        \"collectModuleReturnData\",\n        \"referenceModule\",\n        \"referenceModuleReturnData\",\n        \"timestamp\"\n      ]\n    }\n  },\n  \"required\": [\n    \"dataAvailabilityId\",\n    \"type\",\n    \"timestampProofs\",\n    \"chainProofs\",\n    \"publicationId\",\n    \"event\"\n  ]\n}\n```\n\n##### V2 metadata\n\n```json\n{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"type\": \"object\",\n  \"title\": \"Momoka schema for post v2\",\n  \"properties\": {\n    \"signature\": {\n      \"description\": \"The signature of the entire payload signed by the submitter\",\n      \"type\": \"string\"\n    },\n    \"dataAvailabilityId\": {\n      \"type\": \"string\",\n      \"description\": \"The id of the publication on the data availability layer; it is just a GUID\"\n    },\n    \"type\": {\n      \"description\": \"`POST_CREATED`, `COMMENT_CREATED`, `MIRROR_CREATED` the DA action type which has been submitted\",\n      \"type\": \"POST_CREATED\"\n    },\n    \"timestampProofs\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"type\": {\n          \"description\": \"`BUNDLR` - who has supplied us with the timestamp proofs\",\n          \"type\": \"string\"\n        },\n        \"hashPrefix\": {\n          \"description\": \"The timestamp proof hash prefix\",\n          \"type\": \"number\"\n        },\n        \"response\": {\n          \"description\": \"The response from the timestamp proof provider\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"id\": {\n              \"description\": \"The id of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"timestamp\": {\n              \"description\": \"The timestamp date in milliseconds\",\n              \"type\": \"number\"\n            },\n            \"version\": {\n              \"description\": \"The version of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"public\": {\n              \"description\": \"The public key used sign for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"signature\": {\n              \"description\": \"The signature for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"deadlineHeight\": {\n              \"description\": \"Internal deadline height for the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"block\": {\n              \"description\": \"Internal block for the timestamp proof (this is not an evm block)\",\n              \"type\": \"number\"\n            },\n            \"validatorSignatures\": {\n              \"description\": \"Internal validator signatures for the timestamp proof (this will always be an empty array for now until Bundlr is decentralised)\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          },\n          \"required\": [\n            \"id\",\n            \"timestamp\",\n            \"version\",\n            \"public\",\n            \"signature\",\n            \"deadlineHeight\",\n            \"block\",\n            \"validatorSignatures\"\n          ]\n        }\n      },\n      \"required\": [\"type\", \"hashPrefix\", \"response\"]\n    },\n    \"chainProofs\": {\n      \"description\": \"The proofs\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"thisPublication\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"signature\": {\n              \"description\": \"The transaction signature\",\n              \"type\": \"string\"\n            },\n            \"signedByDelegate\": {\n              \"description\": \"If the signature was signed by a delegate/dispatcher\",\n              \"type\": \"boolean\"\n            },\n            \"signatureDeadline\": {\n              \"description\": \"The deadline of the signature in unix form\",\n              \"type\": \"number\"\n            },\n            \"typedData\": {\n              \"description\": \"The typed data of the transaction; this uses the signed typed data spec\",\n              \"type\": \"object\",\n              \"properties\": {\n                \"types\": {\n                  \"description\": \"The types of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"Post\": {\n                      \"description\": \"The properties of the typed data\",\n                      \"type\": \"array\",\n                      \"items\": {\n                        \"description\": \"The name and type of the property\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                          \"name\": {\n                            \"description\": \"The name of typed data\",\n                            \"type\": \"string\"\n                          },\n                          \"type\": {\n                            \"description\": \"The type typed data\",\n                            \"type\": \"string\"\n                          }\n                        },\n                        \"required\": [\"name\", \"type\"]\n                      }\n                    }\n                  },\n                  \"required\": [\"types\"]\n                },\n                \"domain\": {\n                  \"description\": \"The domain of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"name\": {\n                      \"description\": \"The name of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"version\": {\n                      \"description\": \"The version of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"chainId\": {\n                      \"description\": \"The chain id of the signed typed data\",\n                      \"type\": \"number\"\n                    },\n                    \"verifyingContract\": {\n                      \"description\": \"The verifying contract\",\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"required\": [\n                    \"name\",\n                    \"version\",\n                    \"chainId\",\n                    \"verifyingContract\"\n                  ]\n                },\n                \"value\": {\n                  \"description\": \"The value of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"profileId\": {\n                      \"description\": \"The profile id doing the publication\",\n                      \"type\": \"string\"\n                    },\n                    \"contentURI\": {\n                      \"description\": \"The content metadata URI\",\n                      \"type\": \"string\"\n                    },\n                    \"actionModules\": {\n                      \"description\": \"The action modules - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"actionModulesInitDatas\": {\n                      \"description\": \"The action modules init datas - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"referenceModule\": {\n                      \"description\": \"The reference module will always be address(0) for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModuleInitData\": {\n                      \"description\": \"The reference module init data will - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"nonce\": {\n                      \"description\": \"The signature nonce\",\n                      \"type\": \"number\"\n                    },\n                    \"deadline\": {\n                      \"description\": \"The signature deadline in unix form\",\n                      \"type\": \"number\"\n                    }\n                  },\n                  \"required\": [\n                    \"profileId\",\n                    \"contentURI\",\n                    \"collectModule\",\n                    \"collectModuleInitData\",\n                    \"referenceModule\",\n                    \"referenceModuleInitData\",\n                    \"nonce\",\n                    \"deadline\"\n                  ]\n                }\n              },\n              \"required\": [\"types\", \"domain\", \"value\"]\n            },\n            \"blockHash\": {\n              \"description\": \"The block hash the submitter simulated this transaction on\",\n              \"type\": \"string\"\n            },\n            \"blockNumber\": {\n              \"description\": \"The block number the submitter simulated this transaction on\",\n              \"type\": \"number\"\n            },\n            \"blockTimestamp\": {\n              \"description\": \"The block unix timestamp of the simulated transaction\",\n              \"type\": \"number\"\n            }\n          },\n          \"required\": [\n            \"signature\",\n            \"signedByDelegate\",\n            \"signatureDeadline\",\n            \"typedData\",\n            \"blockHash\",\n            \"blockNumber\",\n            \"blockTimestamp\"\n          ]\n        }\n      },\n      \"required\": [\"thisPublication\"]\n    },\n    \"publicationId\": {\n      \"description\": \"The id of the publication, which is built up of the profileId + pubId + `DA` + first eight chars of the dataAvailabilityId (so it will always be unique)\",\n      \"type\": \"string\"\n    },\n    \"event\": {\n      \"type\": \"object\",\n      \"description\": \"This is trying to shape what you would get within an `EVM` event so you can easily parse it and understand it. This will always be identical to the EVM event data structure.\",\n      \"properties\": {\n        \"postParams\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"profileId\": {\n              \"type\": \"string\",\n              \"description\": \"The profileId which did the publication\"\n            },\n            \"contentURI\": {\n              \"type\": \"string\",\n              \"description\": \"The contentURI aka metadata for the publication\"\n            },\n            \"actionModules\": {\n              \"type\": \"array\",\n              \"description\": \"The array of action modules, for now this will always be empty\"\n            },\n            \"actionModulesInitDatas\": {\n              \"type\": \"array\",\n              \"description\": \"The array of action modules init data, for now this will always be empty\"\n            },\n            \"referenceModule\": {\n              \"type\": \"string\",\n              \"description\": \"The reference module, will always be address(0) for now\"\n            },\n            \"referenceModuleInitData\": {\n              \"type\": \"string\",\n              \"description\": \"The reference module init data, will always for now be empty byte\"\n            }\n          },\n          \"required\": [\n            \"profileId\",\n            \"contentURI\",\n            \"actionModules\",\n            \"actionModulesInitDatas\",\n            \"referenceModule\",\n            \"referenceModuleInitData\"\n          ]\n        },\n        \"pubId\": {\n          \"type\": \"string\",\n          \"description\": \"The pubId for the publication\"\n        },\n        \"actionModulesInitReturnDatas\": {\n          \"type\": \"array\",\n          \"description\": \"The action modules init return datas, will always be empty for now\"\n        },\n        \"referenceModuleInitReturnData\": {\n          \"type\": \"string\",\n          \"description\": \"The reference module init return data, will always for now be empty byte\"\n        },\n        \"transactionExecutor\": {\n          \"type\": \"string\",\n          \"description\": \"The address who executed transaction\"\n        },\n        \"timestamp\": {\n          \"description\": \"The timestamp date in milliseconds\",\n          \"type\": \"number\"\n        }\n      },\n      \"required\": [\n        \"postParams\",\n        \"pubId\",\n        \"actionModulesInitReturnDatas\",\n        \"referenceModuleInitReturnData\",\n        \"transactionExecutor\",\n        \"timestamp\"\n      ]\n    }\n  },\n  \"required\": [\n    \"signature\",\n    \"dataAvailabilityId\",\n    \"type\",\n    \"timestampProofs\",\n    \"chainProofs\",\n    \"publicationId\",\n    \"event\"\n  ]\n}\n```\n\n#### COMMENT_CREATED\n\nThis is a DA comment. Very similar to DA post minus the `type`, `typedData` and some `events` properties\n\n##### V1 metadata\n\n```json\n{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"title\": \"The data availability layer schema\",\n  \"description\": \"The data availability layer schema\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"dataAvailabilityId\": {\n      \"description\": \"The id of the publication on the data availability layer; it is just a GUID\",\n      \"type\": \"guid\"\n    },\n    \"signature\": {\n      \"description\": \"The signature of the entire payload signed by the submitter\",\n      \"type\": \"string\"\n    },\n    \"type\": {\n      \"description\": \"`POST_CREATED`, `COMMENT_CREATED`, `MIRROR_CREATED` the DA action type which has been submitted\",\n      \"type\": \"COMMENT_CREATED\"\n    },\n    \"timestampProofs\": {\n      \"description\": \"Details for the timestamp proofs\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"type\": {\n          \"description\": \"`BUNDLR` - who has supplied us with the timestamp proofs\",\n          \"type\": \"string\"\n        },\n        \"hashPrefix\": {\n          \"description\": \"The timestamp proof hash prefix\",\n          \"type\": \"number\"\n        },\n        \"response\": {\n          \"description\": \"The response from the timestamp proof provider\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"id\": {\n              \"description\": \"The id of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"timestamp\": {\n              \"description\": \"The timestamp date in milliseconds\",\n              \"type\": \"number\"\n            },\n            \"version\": {\n              \"description\": \"The version of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"public\": {\n              \"description\": \"The public key used sign for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"signature\": {\n              \"description\": \"The signature for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"deadlineHeight\": {\n              \"description\": \"Internal deadline height for the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"block\": {\n              \"description\": \"Internal block for the timestamp proof (this is not an evm block)\",\n              \"type\": \"number\"\n            },\n            \"validatorSignatures\": {\n              \"description\": \"Internal validator signatures for the timestamp proof (this will always be an empty array for now until Bundlr is decentralised)\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          },\n          \"required\": [\n            \"id\",\n            \"timestamp\",\n            \"version\",\n            \"public\",\n            \"signature\",\n            \"deadlineHeight\",\n            \"block\",\n            \"validatorSignatures\"\n          ]\n        }\n      },\n      \"required\": [\"type\", \"hashPrefix\", \"response\"]\n    },\n    \"chainProofs\": {\n      \"description\": \"The proofs\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"thisPublication\": {\n          \"description\": \"The publication being submitted\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"signature\": {\n              \"description\": \"The transaction signature\",\n              \"type\": \"string\"\n            },\n            \"signedByDelegate\": {\n              \"description\": \"If the signature was signed by a delegate/dispatcher\",\n              \"type\": \"boolean\"\n            },\n            \"signatureDeadline\": {\n              \"description\": \"The deadline of the signature in unix form\",\n              \"type\": \"number\"\n            },\n            \"typedData\": {\n              \"description\": \"The typed data of the transaction; this uses the signed typed data spec\",\n              \"type\": \"object\",\n              \"properties\": {\n                \"types\": {\n                  \"description\": \"The types of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"CommentWithSig\": {\n                      \"description\": \"The properties of the typed data\",\n                      \"type\": \"array\",\n                      \"items\": {\n                        \"description\": \"The name and type of the property\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                          \"name\": {\n                            \"description\": \"The name of typed data\",\n                            \"type\": \"string\"\n                          },\n                          \"type\": {\n                            \"description\": \"The type typed data\",\n                            \"type\": \"string\"\n                          }\n                        },\n                        \"required\": [\"name\", \"type\"]\n                      }\n                    }\n                  },\n                  \"required\": [\"types\"]\n                },\n                \"domain\": {\n                  \"description\": \"The domain of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"name\": {\n                      \"description\": \"The name of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"version\": {\n                      \"description\": \"The version of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"chainId\": {\n                      \"description\": \"The chain id of the signed typed data\",\n                      \"type\": \"number\"\n                    },\n                    \"verifyingContract\": {\n                      \"description\": \"The verifying contract\",\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"required\": [\n                    \"name\",\n                    \"version\",\n                    \"chainId\",\n                    \"verifyingContract\"\n                  ]\n                },\n                \"value\": {\n                  \"description\": \"The value of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"profileId\": {\n                      \"description\": \"The profile id doing the comment\",\n                      \"type\": \"string\"\n                    },\n                    \"profileIdPointed\": {\n                      \"description\": \"The profile id which the comment is being made on\",\n                      \"type\": \"string\"\n                    },\n                    \"pubIdPointed\": {\n                      \"description\": \"The publication id which the comment is being made on\",\n                      \"type\": \"string\"\n                    },\n                    \"contentURI\": {\n                      \"description\": \"The content metadata URI\",\n                      \"type\": \"string\"\n                    },\n                    \"collectModule\": {\n                      \"description\": \"The collect module address - will always be a revert collect module at the moment\",\n                      \"type\": \"string\"\n                    },\n                    \"collectModuleInitData\": {\n                      \"description\": \"The collect module init data - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModule\": {\n                      \"description\": \"The reference module will always be address(0) for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModuleData\": {\n                      \"description\": \"The reference module data - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModuleInitData\": {\n                      \"description\": \"The reference module init data - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"nonce\": {\n                      \"description\": \"The signature nonce\",\n                      \"type\": \"number\"\n                    },\n                    \"deadline\": {\n                      \"description\": \"The signature deadline in unix form\",\n                      \"type\": \"number\"\n                    }\n                  },\n                  \"required\": [\n                    \"profileId\",\n                    \"profileIdPointed\",\n                    \"pubIdPointed\",\n                    \"contentURI\",\n                    \"collectModule\",\n                    \"collectModuleInitData\",\n                    \"referenceModule\",\n                    \"referenceModuleInitData\",\n                    \"referenceModuleData\",\n                    \"nonce\",\n                    \"deadline\"\n                  ]\n                }\n              },\n              \"required\": [\"types\", \"domain\", \"value\"]\n            },\n            \"blockHash\": {\n              \"description\": \"The block hash the submitter simulated this transaction on\",\n              \"type\": \"string\"\n            },\n            \"blockNumber\": {\n              \"description\": \"The block number the submitter simulated this transaction on\",\n              \"type\": \"number\"\n            },\n            \"blockTimestamp\": {\n              \"description\": \"The block unix timestamp of the simulated transaction\",\n              \"type\": \"number\"\n            }\n          },\n          \"required\": [\n            \"signature\",\n            \"signedByDelegate\",\n            \"signatureDeadline\",\n            \"typedData\",\n            \"blockHash\",\n            \"blockNumber\",\n            \"blockTimestamp\"\n          ]\n        },\n        \"pointer\": {\n          \"description\": \"The pointer this publication is referencing\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"location\": {\n              \"description\": \"The location of the pointer publication proofs on the data availability layer\",\n              \"type\": \"string\"\n            },\n            \"type\": {\n              \"description\": \"the type of the publication on the data availability layer `ON_DA` or `ON_EVM_CHAIN` - for now you can not do a DA publication on a on-chain publication so will always be `ON_DA`\",\n              \"type\": \"string\"\n            }\n          },\n          \"required\": [\"location\", \"type\"]\n        }\n      },\n      \"required\": [\"thisPublication\", \"pointer\"]\n    },\n    \"publicationId\": {\n      \"description\": \"The id of the publication, which is built up of the profileId + pubId + `DA` + first eight chars of the dataAvailabilityId (so it will always be unique)\",\n      \"type\": \"string\"\n    },\n    \"event\": {\n      \"description\": \"This is trying to shape what you would get within an `EVM` event so you can easily parse it and understand it. This will always be identical to the EVM event data structure.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"profileId\": {\n          \"description\": \"The profileId which did the publication\",\n          \"type\": \"string\"\n        },\n        \"pubId\": {\n          \"description\": \"The pubId for the publication\",\n          \"type\": \"string\"\n        },\n        \"contentURI\": {\n          \"description\": \"The contentURI aka metadata for the publication\",\n          \"type\": \"string\"\n        },\n        \"profileIdPointed\": {\n          \"description\": \"The profile id of the comment is being made on\",\n          \"type\": \"string\"\n        },\n        \"pubIdPointed\": {\n          \"description\": \"The pub id which the comment is being made on\",\n          \"type\": \"string\"\n        },\n        \"referenceModuleData\": {\n          \"description\": \"The reference module data - will always be empty hex for now\",\n          \"type\": \"string\"\n        },\n        \"collectModule\": {\n          \"description\": \"The collect module, for now it will always be revert module\",\n          \"type\": \"string\"\n        },\n        \"collectModuleReturnData\": {\n          \"description\": \"The collect module return data, will always for now be empty byte\",\n          \"type\": \"string\"\n        },\n        \"referenceModule\": {\n          \"description\": \"The reference module, will always be address(0) for now\",\n          \"type\": \"string\"\n        },\n        \"referenceModuleReturnData\": {\n          \"description\": \"The reference module return data, will always for now be empty byte\",\n          \"type\": \"string\"\n        },\n        \"timestamp\": {\n          \"description\": \"The timestamp date in milliseconds\",\n          \"type\": \"number\"\n        }\n      },\n      \"required\": [\n        \"profileId\",\n        \"pubId\",\n        \"contentURI\",\n        \"profileIdPointed\",\n        \"pubIdPointed\",\n        \"referenceModuleData\",\n        \"collectModule\",\n        \"collectModuleReturnData\",\n        \"referenceModule\",\n        \"referenceModuleReturnData\",\n        \"timestamp\"\n      ]\n    }\n  },\n  \"required\": [\n    \"dataAvailabilityId\",\n    \"type\",\n    \"timestampProofs\",\n    \"chainProofs\",\n    \"publicationId\",\n    \"event\"\n  ]\n}\n```\n\n##### V2 metadata\n\n```json\n{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"type\": \"object\",\n  \"title\": \"Momoka schema for comment v2\",\n  \"properties\": {\n    \"signature\": {\n      \"description\": \"The signature of the entire payload signed by the submitter\",\n      \"type\": \"string\"\n    },\n    \"dataAvailabilityId\": {\n      \"type\": \"string\",\n      \"description\": \"The id of the publication on the data availability layer; it is just a GUID\"\n    },\n    \"type\": {\n      \"description\": \"`POST_CREATED`, `COMMENT_CREATED`, `MIRROR_CREATED` the DA action type which has been submitted\",\n      \"type\": \"COMMENT_CREATED\"\n    },\n    \"timestampProofs\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"type\": {\n          \"description\": \"`BUNDLR` - who has supplied us with the timestamp proofs\",\n          \"type\": \"string\"\n        },\n        \"hashPrefix\": {\n          \"description\": \"The timestamp proof hash prefix\",\n          \"type\": \"number\"\n        },\n        \"response\": {\n          \"description\": \"The response from the timestamp proof provider\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"id\": {\n              \"description\": \"The id of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"timestamp\": {\n              \"description\": \"The timestamp date in milliseconds\",\n              \"type\": \"number\"\n            },\n            \"version\": {\n              \"description\": \"The version of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"public\": {\n              \"description\": \"The public key used sign for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"signature\": {\n              \"description\": \"The signature for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"deadlineHeight\": {\n              \"description\": \"Internal deadline height for the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"block\": {\n              \"description\": \"Internal block for the timestamp proof (this is not an evm block)\",\n              \"type\": \"number\"\n            },\n            \"validatorSignatures\": {\n              \"description\": \"Internal validator signatures for the timestamp proof (this will always be an empty array for now until Bundlr is decentralised)\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          },\n          \"required\": [\n            \"id\",\n            \"timestamp\",\n            \"version\",\n            \"public\",\n            \"signature\",\n            \"deadlineHeight\",\n            \"block\",\n            \"validatorSignatures\"\n          ]\n        }\n      },\n      \"required\": [\"type\", \"hashPrefix\", \"response\"]\n    },\n    \"chainProofs\": {\n      \"description\": \"The proofs\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"thisPublication\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"signature\": {\n              \"description\": \"The transaction signature\",\n              \"type\": \"string\"\n            },\n            \"signedByDelegate\": {\n              \"description\": \"If the signature was signed by a delegate/dispatcher\",\n              \"type\": \"boolean\"\n            },\n            \"signatureDeadline\": {\n              \"description\": \"The deadline of the signature in unix form\",\n              \"type\": \"number\"\n            },\n            \"typedData\": {\n              \"description\": \"The typed data of the transaction; this uses the signed typed data spec\",\n              \"type\": \"object\",\n              \"properties\": {\n                \"types\": {\n                  \"description\": \"The types of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"Comment\": {\n                      \"description\": \"The properties of the typed data\",\n                      \"type\": \"array\",\n                      \"items\": {\n                        \"description\": \"The name and type of the property\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                          \"name\": {\n                            \"description\": \"The name of typed data\",\n                            \"type\": \"string\"\n                          },\n                          \"type\": {\n                            \"description\": \"The type typed data\",\n                            \"type\": \"string\"\n                          }\n                        },\n                        \"required\": [\"name\", \"type\"]\n                      }\n                    }\n                  },\n                  \"required\": [\"types\"]\n                },\n                \"domain\": {\n                  \"description\": \"The domain of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"name\": {\n                      \"description\": \"The name of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"version\": {\n                      \"description\": \"The version of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"chainId\": {\n                      \"description\": \"The chain id of the signed typed data\",\n                      \"type\": \"number\"\n                    },\n                    \"verifyingContract\": {\n                      \"description\": \"The verifying contract\",\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"required\": [\n                    \"name\",\n                    \"version\",\n                    \"chainId\",\n                    \"verifyingContract\"\n                  ]\n                },\n                \"value\": {\n                  \"description\": \"The value of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"profileId\": {\n                      \"description\": \"The profile id doing the publication\",\n                      \"type\": \"string\"\n                    },\n                    \"pointedProfileId\": {\n                      \"description\": \"The profile id which the comment is being made on\",\n                      \"type\": \"string\"\n                    },\n                    \"pointedPubId\": {\n                      \"description\": \"The publication id which the comment is being made on\",\n                      \"type\": \"string\"\n                    },\n                    \"contentURI\": {\n                      \"description\": \"The content metadata URI\",\n                      \"type\": \"string\"\n                    },\n                    \"actionModules\": {\n                      \"description\": \"The action modules - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"actionModulesInitDatas\": {\n                      \"description\": \"The action modules init datas - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"referenceModule\": {\n                      \"description\": \"The reference module will always be address(0) for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModuleData\": {\n                      \"description\": \"The reference module data - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModuleInitData\": {\n                      \"description\": \"The reference module init data will - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referrerProfileIds\": {\n                      \"description\": \"The profile ids this publication references - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"referrerPubIds\": {\n                      \"description\": \"The pub ids this publication references - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"nonce\": {\n                      \"description\": \"The signature nonce\",\n                      \"type\": \"number\"\n                    },\n                    \"deadline\": {\n                      \"description\": \"The signature deadline in unix form\",\n                      \"type\": \"number\"\n                    }\n                  },\n                  \"required\": [\n                    \"profileId\",\n                    \"pointedProfileId\",\n                    \"pointedPubId\",\n                    \"contentURI\",\n                    \"actionModules\",\n                    \"actionModulesInitDatas\",\n                    \"referenceModule\",\n                    \"referenceModuleData\",\n                    \"referenceModuleInitData\",\n                    \"referrerProfileIds\",\n                    \"referrerPubIds\",\n                    \"nonce\",\n                    \"deadline\"\n                  ]\n                }\n              },\n              \"required\": [\"types\", \"domain\", \"value\"]\n            },\n            \"blockHash\": {\n              \"description\": \"The block hash the submitter simulated this transaction on\",\n              \"type\": \"string\"\n            },\n            \"blockNumber\": {\n              \"description\": \"The block number the submitter simulated this transaction on\",\n              \"type\": \"number\"\n            },\n            \"blockTimestamp\": {\n              \"description\": \"The block unix timestamp of the simulated transaction\",\n              \"type\": \"number\"\n            }\n          },\n          \"required\": [\n            \"signature\",\n            \"signedByDelegate\",\n            \"signatureDeadline\",\n            \"typedData\",\n            \"blockHash\",\n            \"blockNumber\",\n            \"blockTimestamp\"\n          ]\n        }\n      },\n      \"required\": [\"thisPublication\"]\n    },\n    \"publicationId\": {\n      \"description\": \"The id of the publication, which is built up of the profileId + pubId + `DA` + first eight chars of the dataAvailabilityId (so it will always be unique)\",\n      \"type\": \"string\"\n    },\n    \"event\": {\n      \"type\": \"object\",\n      \"description\": \"This is trying to shape what you would get within an `EVM` event so you can easily parse it and understand it. This will always be identical to the EVM event data structure.\",\n      \"properties\": {\n        \"commentParams\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"profileId\": {\n              \"type\": \"string\",\n              \"description\": \"The profileId which did the publication\"\n            },\n            \"contentURI\": {\n              \"type\": \"string\",\n              \"description\": \"The contentURI aka metadata for the publication\"\n            },\n            \"actionModules\": {\n              \"type\": \"array\",\n              \"description\": \"The array of action modules, for now this will always be empty\"\n            },\n            \"actionModulesInitDatas\": {\n              \"type\": \"array\",\n              \"description\": \"The array of action modules init data, for now this will always be empty\"\n            },\n            \"referenceModule\": {\n              \"type\": \"string\",\n              \"description\": \"The reference module, will always be address(0) for now\"\n            },\n            \"referenceModuleInitData\": {\n              \"type\": \"string\",\n              \"description\": \"The reference module init data, will always for now be empty byte\"\n            },\n            \"referrerProfileIds\": {\n              \"description\": \"The profile ids this publication references - will always be empty for now\",\n              \"type\": \"array\"\n            },\n            \"referrerPubIds\": {\n              \"description\": \"The pub ids this publication references - will always be empty for now\",\n              \"type\": \"array\"\n            },\n\n            \"pointedProfileId\": {\n              \"description\": \"The profile id of the comment is being made on\",\n              \"type\": \"string\"\n            },\n            \"pointedPubId\": {\n              \"description\": \"The pub ids this publication references - will always be empty for now\",\n              \"type\": \"string\"\n            }\n          },\n          \"required\": [\n            \"profileId\",\n            \"contentURI\",\n            \"actionModules\",\n            \"actionModulesInitDatas\",\n            \"referenceModule\",\n            \"referenceModuleInitData\",\n            \"referrerProfileIds\",\n            \"referrerPubIds\",\n            \"pointedProfileId\",\n            \"pointedPubId\"\n          ]\n        },\n        \"pubId\": {\n          \"type\": \"string\",\n          \"description\": \"The pubId for the publication\"\n        },\n        \"actionModulesInitReturnDatas\": {\n          \"type\": \"array\",\n          \"description\": \"The action modules init return datas, will always be empty for now\"\n        },\n        \"referenceModuleReturnData\": {\n          \"description\": \"The reference module return data, will always for now be empty byte\",\n          \"type\": \"string\"\n        },\n        \"referenceModuleInitReturnData\": {\n          \"type\": \"string\",\n          \"description\": \"The reference module init return data, will always for now be empty byte\"\n        },\n        \"transactionExecutor\": {\n          \"type\": \"string\",\n          \"description\": \"The address who executed transaction\"\n        },\n        \"timestamp\": {\n          \"description\": \"The timestamp date in milliseconds\",\n          \"type\": \"number\"\n        }\n      },\n      \"required\": [\n        \"commentParams\",\n        \"pubId\",\n        \"actionModulesInitReturnDatas\",\n        \"referenceModuleReturnData\",\n        \"referenceModuleInitReturnData\",\n        \"transactionExecutor\",\n        \"timestamp\"\n      ]\n    }\n  },\n  \"required\": [\n    \"signature\",\n    \"dataAvailabilityId\",\n    \"type\",\n    \"timestampProofs\",\n    \"chainProofs\",\n    \"publicationId\",\n    \"event\"\n  ]\n}\n```\n\n#### MIRROR_CREATED\n\nThis is a DA mirror. Very similar to DA post/comment minus the `type`, `typedData` and some `events` properties\n\n##### V1 metadata\n\n```json\n{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"title\": \"The data availability layer schema\",\n  \"description\": \"The data availability layer schema\",\n  \"type\": \"object\",\n  \"properties\": {\n    \"dataAvailabilityId\": {\n      \"description\": \"The id of the publication on the data availability layer; it is just a GUID\",\n      \"type\": \"guid\"\n    },\n    \"signature\": {\n      \"description\": \"The signature of the entire payload signed by the submitter\",\n      \"type\": \"string\"\n    },\n    \"type\": {\n      \"description\": \"`POST_CREATED`, `COMMENT_CREATED`, `MIRROR_CREATED` the DA action type which has been submitted\",\n      \"type\": \"COMMENT_CREATED\"\n    },\n    \"timestampProofs\": {\n      \"description\": \"Details for the timestamp proofs\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"type\": {\n          \"description\": \"`BUNDLR` - who has supplied us with the timestamp proofs\",\n          \"type\": \"string\"\n        },\n        \"hashPrefix\": {\n          \"description\": \"The timestamp proof hash prefix\",\n          \"type\": \"number\"\n        },\n        \"response\": {\n          \"description\": \"The response from the timestamp proof provider\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"id\": {\n              \"description\": \"The id of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"timestamp\": {\n              \"description\": \"The timestamp date in milliseconds\",\n              \"type\": \"number\"\n            },\n            \"version\": {\n              \"description\": \"The version of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"public\": {\n              \"description\": \"The public key used sign for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"signature\": {\n              \"description\": \"The signature for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"deadlineHeight\": {\n              \"description\": \"Internal deadline height for the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"block\": {\n              \"description\": \"Internal block for the timestamp proof (this is not an evm block)\",\n              \"type\": \"number\"\n            },\n            \"validatorSignatures\": {\n              \"description\": \"Internal validator signatures for the timestamp proof (this will always be an empty array for now until Bundlr is decentralised)\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          },\n          \"required\": [\n            \"id\",\n            \"timestamp\",\n            \"version\",\n            \"public\",\n            \"signature\",\n            \"deadlineHeight\",\n            \"block\",\n            \"validatorSignatures\"\n          ]\n        }\n      },\n      \"required\": [\"type\", \"hashPrefix\", \"response\"]\n    },\n    \"chainProofs\": {\n      \"description\": \"The proofs\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"thisPublication\": {\n          \"description\": \"The publication being submitted\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"signature\": {\n              \"description\": \"The transaction signature\",\n              \"type\": \"string\"\n            },\n            \"signedByDelegate\": {\n              \"description\": \"If the signature was signed by a delegate/dispatcher\",\n              \"type\": \"boolean\"\n            },\n            \"signatureDeadline\": {\n              \"description\": \"The deadline of the signature in unix form\",\n              \"type\": \"number\"\n            },\n            \"typedData\": {\n              \"description\": \"The typed data of the transaction; this uses the signed typed data spec\",\n              \"type\": \"object\",\n              \"properties\": {\n                \"types\": {\n                  \"description\": \"The types of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"MirrorWithSig\": {\n                      \"description\": \"The properties of the typed data\",\n                      \"type\": \"array\",\n                      \"items\": {\n                        \"description\": \"The name and type of the property\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                          \"name\": {\n                            \"description\": \"The name of typed data\",\n                            \"type\": \"string\"\n                          },\n                          \"type\": {\n                            \"description\": \"The type typed data\",\n                            \"type\": \"string\"\n                          }\n                        },\n                        \"required\": [\"name\", \"type\"]\n                      }\n                    }\n                  },\n                  \"required\": [\"types\"]\n                },\n                \"domain\": {\n                  \"description\": \"The domain of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"name\": {\n                      \"description\": \"The name of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"version\": {\n                      \"description\": \"The version of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"chainId\": {\n                      \"description\": \"The chain id of the signed typed data\",\n                      \"type\": \"number\"\n                    },\n                    \"verifyingContract\": {\n                      \"description\": \"The verifying contract\",\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"required\": [\n                    \"name\",\n                    \"version\",\n                    \"chainId\",\n                    \"verifyingContract\"\n                  ]\n                },\n                \"value\": {\n                  \"description\": \"The value of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"profileId\": {\n                      \"description\": \"The profile id doing the comment\",\n                      \"type\": \"string\"\n                    },\n                    \"profileIdPointed\": {\n                      \"description\": \"The profile id which the comment is being made on\",\n                      \"type\": \"string\"\n                    },\n                    \"pubIdPointed\": {\n                      \"description\": \"The publication id which the comment is being made on\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModule\": {\n                      \"description\": \"The reference module will always be address(0) for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModuleData\": {\n                      \"description\": \"The reference module data - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModuleInitData\": {\n                      \"description\": \"The reference module init data - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"nonce\": {\n                      \"description\": \"The signature nonce\",\n                      \"type\": \"number\"\n                    },\n                    \"deadline\": {\n                      \"description\": \"The signature deadline in unix form\",\n                      \"type\": \"number\"\n                    }\n                  },\n                  \"required\": [\n                    \"profileId\",\n                    \"profileIdPointed\",\n                    \"pubIdPointed\",\n                    \"referenceModule\",\n                    \"referenceModuleInitData\",\n                    \"referenceModuleData\",\n                    \"nonce\",\n                    \"deadline\"\n                  ]\n                }\n              },\n              \"required\": [\"types\", \"domain\", \"value\"]\n            },\n            \"blockHash\": {\n              \"description\": \"The block hash the submitter simulated this transaction on\",\n              \"type\": \"string\"\n            },\n            \"blockNumber\": {\n              \"description\": \"The block number the submitter simulated this transaction on\",\n              \"type\": \"number\"\n            },\n            \"blockTimestamp\": {\n              \"description\": \"The block unix timestamp of the simulated transaction\",\n              \"type\": \"number\"\n            }\n          },\n          \"required\": [\n            \"signature\",\n            \"signedByDelegate\",\n            \"signatureDeadline\",\n            \"typedData\",\n            \"blockHash\",\n            \"blockNumber\",\n            \"blockTimestamp\"\n          ]\n        },\n        \"pointer\": {\n          \"description\": \"The pointer this publication is referencing\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"location\": {\n              \"description\": \"The location of the pointer publication proofs on the data availability layer\",\n              \"type\": \"string\"\n            },\n            \"type\": {\n              \"description\": \"the type of the publication on the data availability layer `ON_DA` or `ON_EVM_CHAIN` - for now you can not do a DA publication on a on-chain publication so will always be `ON_DA`\",\n              \"type\": \"string\"\n            }\n          },\n          \"required\": [\"location\", \"type\"]\n        }\n      },\n      \"required\": [\"thisPublication\", \"pointer\"]\n    },\n    \"publicationId\": {\n      \"description\": \"The id of the publication, which is built up of the profileId + pubId + `DA` + first eight chars of the dataAvailabilityId (so it will always be unique)\",\n      \"type\": \"string\"\n    },\n    \"event\": {\n      \"description\": \"This is trying to shape what you would get within an `EVM` event so you can easily parse it and understand it. This will always be identical to the EVM event data structure.\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"profileId\": {\n          \"description\": \"The profileId which did the mirror\",\n          \"type\": \"string\"\n        },\n        \"pubId\": {\n          \"description\": \"The pubId for the mirror\",\n          \"type\": \"string\"\n        },\n        \"profileIdPointed\": {\n          \"description\": \"The profile id of the mirror is being made on\",\n          \"type\": \"string\"\n        },\n        \"pubIdPointed\": {\n          \"description\": \"The pub id which the mirror is being made on\",\n          \"type\": \"string\"\n        },\n        \"referenceModuleData\": {\n          \"description\": \"The reference module data - will always be empty hex for now\",\n          \"type\": \"string\"\n        },\n        \"referenceModule\": {\n          \"description\": \"The reference module, will always be address(0) for now\",\n          \"type\": \"string\"\n        },\n        \"referenceModuleReturnData\": {\n          \"description\": \"The reference module return data, will always for now be empty byte\",\n          \"type\": \"string\"\n        },\n        \"timestamp\": {\n          \"description\": \"The timestamp date in milliseconds\",\n          \"type\": \"number\"\n        }\n      },\n      \"required\": [\n        \"profileId\",\n        \"pubId\",\n        \"profileIdPointed\",\n        \"pubIdPointed\",\n        \"referenceModuleData\",\n        \"referenceModule\",\n        \"referenceModuleReturnData\",\n        \"timestamp\"\n      ]\n    }\n  },\n  \"required\": [\n    \"dataAvailabilityId\",\n    \"type\",\n    \"timestampProofs\",\n    \"chainProofs\",\n    \"publicationId\",\n    \"event\"\n  ]\n}\n```\n\n##### V2 metadata\n\n```json\n{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"type\": \"object\",\n  \"title\": \"Momoka schema for mirror v2\",\n  \"properties\": {\n    \"signature\": {\n      \"description\": \"The signature of the entire payload signed by the submitter\",\n      \"type\": \"string\"\n    },\n    \"dataAvailabilityId\": {\n      \"type\": \"string\",\n      \"description\": \"The id of the publication on the data availability layer; it is just a GUID\"\n    },\n    \"type\": {\n      \"description\": \"`POST_CREATED`, `COMMENT_CREATED`, `MIRROR_CREATED` the DA action type which has been submitted\",\n      \"type\": \"MIRROR_CREATED\"\n    },\n    \"timestampProofs\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"type\": {\n          \"description\": \"`BUNDLR` - who has supplied us with the timestamp proofs\",\n          \"type\": \"string\"\n        },\n        \"hashPrefix\": {\n          \"description\": \"The timestamp proof hash prefix\",\n          \"type\": \"number\"\n        },\n        \"response\": {\n          \"description\": \"The response from the timestamp proof provider\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"id\": {\n              \"description\": \"The id of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"timestamp\": {\n              \"description\": \"The timestamp date in milliseconds\",\n              \"type\": \"number\"\n            },\n            \"version\": {\n              \"description\": \"The version of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"public\": {\n              \"description\": \"The public key used sign for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"signature\": {\n              \"description\": \"The signature for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"deadlineHeight\": {\n              \"description\": \"Internal deadline height for the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"block\": {\n              \"description\": \"Internal block for the timestamp proof (this is not an evm block)\",\n              \"type\": \"number\"\n            },\n            \"validatorSignatures\": {\n              \"description\": \"Internal validator signatures for the timestamp proof (this will always be an empty array for now until Bundlr is decentralised)\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          },\n          \"required\": [\n            \"id\",\n            \"timestamp\",\n            \"version\",\n            \"public\",\n            \"signature\",\n            \"deadlineHeight\",\n            \"block\",\n            \"validatorSignatures\"\n          ]\n        }\n      },\n      \"required\": [\"type\", \"hashPrefix\", \"response\"]\n    },\n    \"chainProofs\": {\n      \"description\": \"The proofs\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"thisPublication\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"signature\": {\n              \"description\": \"The transaction signature\",\n              \"type\": \"string\"\n            },\n            \"signedByDelegate\": {\n              \"description\": \"If the signature was signed by a delegate/dispatcher\",\n              \"type\": \"boolean\"\n            },\n            \"signatureDeadline\": {\n              \"description\": \"The deadline of the signature in unix form\",\n              \"type\": \"number\"\n            },\n            \"typedData\": {\n              \"description\": \"The typed data of the transaction; this uses the signed typed data spec\",\n              \"type\": \"object\",\n              \"properties\": {\n                \"types\": {\n                  \"description\": \"The types of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"Mirror\": {\n                      \"description\": \"The properties of the typed data\",\n                      \"type\": \"array\",\n                      \"items\": {\n                        \"description\": \"The name and type of the property\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                          \"name\": {\n                            \"description\": \"The name of typed data\",\n                            \"type\": \"string\"\n                          },\n                          \"type\": {\n                            \"description\": \"The type typed data\",\n                            \"type\": \"string\"\n                          }\n                        },\n                        \"required\": [\"name\", \"type\"]\n                      }\n                    }\n                  },\n                  \"required\": [\"types\"]\n                },\n                \"domain\": {\n                  \"description\": \"The domain of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"name\": {\n                      \"description\": \"The name of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"version\": {\n                      \"description\": \"The version of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"chainId\": {\n                      \"description\": \"The chain id of the signed typed data\",\n                      \"type\": \"number\"\n                    },\n                    \"verifyingContract\": {\n                      \"description\": \"The verifying contract\",\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"required\": [\n                    \"name\",\n                    \"version\",\n                    \"chainId\",\n                    \"verifyingContract\"\n                  ]\n                },\n                \"value\": {\n                  \"description\": \"The value of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"metadataURI\": {\n                      \"description\": \"The metadata URI\",\n                      \"type\": \"string\"\n                    },\n                    \"profileId\": {\n                      \"description\": \"The profile id doing the publication\",\n                      \"type\": \"string\"\n                    },\n                    \"pointedProfileId\": {\n                      \"description\": \"The profile id which the publication is being made on\",\n                      \"type\": \"string\"\n                    },\n                    \"pointedPubId\": {\n                      \"description\": \"The publication id which the publication is being made on\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModuleData\": {\n                      \"description\": \"The reference module data - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referrerProfileIds\": {\n                      \"description\": \"The profile ids this publication references - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"referrerPubIds\": {\n                      \"description\": \"The pub ids this publication references - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"nonce\": {\n                      \"description\": \"The signature nonce\",\n                      \"type\": \"number\"\n                    },\n                    \"deadline\": {\n                      \"description\": \"The signature deadline in unix form\",\n                      \"type\": \"number\"\n                    }\n                  },\n                  \"required\": [\n                    \"profileId\",\n                    \"pointedProfileId\",\n                    \"pointedPubId\",\n                    \"metadataURI\",\n                    \"referenceModuleData\",\n                    \"referrerProfileIds\",\n                    \"referrerPubIds\",\n                    \"nonce\",\n                    \"deadline\"\n                  ]\n                }\n              },\n              \"required\": [\"types\", \"domain\", \"value\"]\n            },\n            \"blockHash\": {\n              \"description\": \"The block hash the submitter simulated this transaction on\",\n              \"type\": \"string\"\n            },\n            \"blockNumber\": {\n              \"description\": \"The block number the submitter simulated this transaction on\",\n              \"type\": \"number\"\n            },\n            \"blockTimestamp\": {\n              \"description\": \"The block unix timestamp of the simulated transaction\",\n              \"type\": \"number\"\n            }\n          },\n          \"required\": [\n            \"signature\",\n            \"signedByDelegate\",\n            \"signatureDeadline\",\n            \"typedData\",\n            \"blockHash\",\n            \"blockNumber\",\n            \"blockTimestamp\"\n          ]\n        }\n      },\n      \"required\": [\"thisPublication\"]\n    },\n    \"publicationId\": {\n      \"description\": \"The id of the publication, which is built up of the profileId + pubId + `DA` + first eight chars of the dataAvailabilityId (so it will always be unique)\",\n      \"type\": \"string\"\n    },\n    \"event\": {\n      \"type\": \"object\",\n      \"description\": \"This is trying to shape what you would get within an `EVM` event so you can easily parse it and understand it. This will always be identical to the EVM event data structure.\",\n      \"properties\": {\n        \"mirrorParams\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"profileId\": {\n              \"type\": \"string\",\n              \"description\": \"The profileId which did the publication\"\n            },\n            \"metadataURI\": {\n              \"type\": \"string\",\n              \"description\": \"The metadataURI aka metadata for the publication\"\n            },\n            \"referenceModuleData\": {\n              \"type\": \"string\",\n              \"description\": \"The reference module data, will always for now be empty byte\"\n            },\n            \"referrerProfileIds\": {\n              \"description\": \"The profile ids this publication references - will always be empty for now\",\n              \"type\": \"array\"\n            },\n            \"referrerPubIds\": {\n              \"description\": \"The pub ids this publication references - will always be empty for now\",\n              \"type\": \"array\"\n            },\n            \"pointedProfileId\": {\n              \"description\": \"The profile id of the publication is being made on\",\n              \"type\": \"string\"\n            },\n            \"pointedPubId\": {\n              \"description\": \"The pub ids this publication references - will always be empty for now\",\n              \"type\": \"string\"\n            }\n          },\n          \"required\": [\n            \"profileId\",\n            \"metadataURI\",\n            \"referenceModuleData\",\n            \"referrerProfileIds\",\n            \"referrerPubIds\",\n            \"pointedProfileId\",\n            \"pointedPubId\"\n          ]\n        },\n        \"pubId\": {\n          \"type\": \"string\",\n          \"description\": \"The pubId for the publication\"\n        },\n        \"referenceModuleReturnData\": {\n          \"description\": \"The reference module return data, will always for now be empty byte\",\n          \"type\": \"string\"\n        },\n        \"transactionExecutor\": {\n          \"type\": \"string\",\n          \"description\": \"The address who executed transaction\"\n        },\n        \"timestamp\": {\n          \"description\": \"The timestamp date in milliseconds\",\n          \"type\": \"number\"\n        }\n      },\n      \"required\": [\n        \"mirrorParams\",\n        \"pubId\",\n        \"actionModulesInitReturnDatas\",\n        \"referenceModuleReturnData\",\n        \"referenceModuleInitReturnData\",\n        \"transactionExecutor\",\n        \"timestamp\"\n      ]\n    }\n  },\n  \"required\": [\n    \"signature\",\n    \"dataAvailabilityId\",\n    \"type\",\n    \"timestampProofs\",\n    \"chainProofs\",\n    \"publicationId\",\n    \"event\"\n  ]\n}\n```\n\n#### QUOTE_CREATED\n\nThis is a DA mirror. It's very similar to the DA comment.\n\n##### V1 metadata\n\nQuote was not available in V1\n\n##### V2 metadata\n\n```json\n{\n  \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n  \"type\": \"object\",\n  \"title\": \"Momoka schema for quote v2\",\n  \"properties\": {\n    \"signature\": {\n      \"description\": \"The signature of the entire payload signed by the submitter\",\n      \"type\": \"string\"\n    },\n    \"dataAvailabilityId\": {\n      \"type\": \"string\",\n      \"description\": \"The id of the publication on the data availability layer; it is just a GUID\"\n    },\n    \"type\": {\n      \"description\": \"`POST_CREATED`, `COMMENT_CREATED`, `MIRROR_CREATED` the DA action type which has been submitted\",\n      \"type\": \"QUOTE_CREATED\"\n    },\n    \"timestampProofs\": {\n      \"type\": \"object\",\n      \"properties\": {\n        \"type\": {\n          \"description\": \"`BUNDLR` - who has supplied us with the timestamp proofs\",\n          \"type\": \"string\"\n        },\n        \"hashPrefix\": {\n          \"description\": \"The timestamp proof hash prefix\",\n          \"type\": \"number\"\n        },\n        \"response\": {\n          \"description\": \"The response from the timestamp proof provider\",\n          \"type\": \"object\",\n          \"properties\": {\n            \"id\": {\n              \"description\": \"The id of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"timestamp\": {\n              \"description\": \"The timestamp date in milliseconds\",\n              \"type\": \"number\"\n            },\n            \"version\": {\n              \"description\": \"The version of the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"public\": {\n              \"description\": \"The public key used sign for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"signature\": {\n              \"description\": \"The signature for the timestamp proofs\",\n              \"type\": \"string\"\n            },\n            \"deadlineHeight\": {\n              \"description\": \"Internal deadline height for the timestamp proof\",\n              \"type\": \"string\"\n            },\n            \"block\": {\n              \"description\": \"Internal block for the timestamp proof (this is not an evm block)\",\n              \"type\": \"number\"\n            },\n            \"validatorSignatures\": {\n              \"description\": \"Internal validator signatures for the timestamp proof (this will always be an empty array for now until Bundlr is decentralised)\",\n              \"type\": \"array\",\n              \"items\": {\n                \"type\": \"string\"\n              }\n            }\n          },\n          \"required\": [\n            \"id\",\n            \"timestamp\",\n            \"version\",\n            \"public\",\n            \"signature\",\n            \"deadlineHeight\",\n            \"block\",\n            \"validatorSignatures\"\n          ]\n        }\n      },\n      \"required\": [\"type\", \"hashPrefix\", \"response\"]\n    },\n    \"chainProofs\": {\n      \"description\": \"The proofs\",\n      \"type\": \"object\",\n      \"properties\": {\n        \"thisPublication\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"signature\": {\n              \"description\": \"The transaction signature\",\n              \"type\": \"string\"\n            },\n            \"signedByDelegate\": {\n              \"description\": \"If the signature was signed by a delegate/dispatcher\",\n              \"type\": \"boolean\"\n            },\n            \"signatureDeadline\": {\n              \"description\": \"The deadline of the signature in unix form\",\n              \"type\": \"number\"\n            },\n            \"typedData\": {\n              \"description\": \"The typed data of the transaction; this uses the signed typed data spec\",\n              \"type\": \"object\",\n              \"properties\": {\n                \"types\": {\n                  \"description\": \"The types of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"Quote\": {\n                      \"description\": \"The properties of the typed data\",\n                      \"type\": \"array\",\n                      \"items\": {\n                        \"description\": \"The name and type of the property\",\n                        \"type\": \"object\",\n                        \"properties\": {\n                          \"name\": {\n                            \"description\": \"The name of typed data\",\n                            \"type\": \"string\"\n                          },\n                          \"type\": {\n                            \"description\": \"The type typed data\",\n                            \"type\": \"string\"\n                          }\n                        },\n                        \"required\": [\"name\", \"type\"]\n                      }\n                    }\n                  },\n                  \"required\": [\"types\"]\n                },\n                \"domain\": {\n                  \"description\": \"The domain of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"name\": {\n                      \"description\": \"The name of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"version\": {\n                      \"description\": \"The version of the signed typed data\",\n                      \"type\": \"string\"\n                    },\n                    \"chainId\": {\n                      \"description\": \"The chain id of the signed typed data\",\n                      \"type\": \"number\"\n                    },\n                    \"verifyingContract\": {\n                      \"description\": \"The verifying contract\",\n                      \"type\": \"string\"\n                    }\n                  },\n                  \"required\": [\n                    \"name\",\n                    \"version\",\n                    \"chainId\",\n                    \"verifyingContract\"\n                  ]\n                },\n                \"value\": {\n                  \"description\": \"The value of the signed typed data\",\n                  \"type\": \"object\",\n                  \"properties\": {\n                    \"profileId\": {\n                      \"description\": \"The profile id doing the publication\",\n                      \"type\": \"string\"\n                    },\n                    \"pointedProfileId\": {\n                      \"description\": \"The profile id which the quote is being made on\",\n                      \"type\": \"string\"\n                    },\n                    \"pointedPubId\": {\n                      \"description\": \"The publication id which the quote is being made on\",\n                      \"type\": \"string\"\n                    },\n                    \"contentURI\": {\n                      \"description\": \"The content metadata URI\",\n                      \"type\": \"string\"\n                    },\n                    \"actionModules\": {\n                      \"description\": \"The action modules - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"actionModulesInitDatas\": {\n                      \"description\": \"The action modules init datas - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"referenceModule\": {\n                      \"description\": \"The reference module will always be address(0) for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModuleData\": {\n                      \"description\": \"The reference module data - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referenceModuleInitData\": {\n                      \"description\": \"The reference module init data will - will always be empty bytes for now\",\n                      \"type\": \"string\"\n                    },\n                    \"referrerProfileIds\": {\n                      \"description\": \"The profile ids this publication references - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"referrerPubIds\": {\n                      \"description\": \"The pub ids this publication references - will always be empty for now\",\n                      \"type\": \"array\"\n                    },\n                    \"nonce\": {\n                      \"description\": \"The signature nonce\",\n                      \"type\": \"number\"\n                    },\n                    \"deadline\": {\n                      \"description\": \"The signature deadline in unix form\",\n                      \"type\": \"number\"\n                    }\n                  },\n                  \"required\": [\n                    \"profileId\",\n                    \"pointedProfileId\",\n                    \"pointedPubId\",\n                    \"contentURI\",\n                    \"actionModules\",\n                    \"actionModulesInitDatas\",\n                    \"referenceModule\",\n                    \"referenceModuleData\",\n                    \"referenceModuleInitData\",\n                    \"referrerProfileIds\",\n                    \"referrerPubIds\",\n                    \"nonce\",\n                    \"deadline\"\n                  ]\n                }\n              },\n              \"required\": [\"types\", \"domain\", \"value\"]\n            },\n            \"blockHash\": {\n              \"description\": \"The block hash the submitter simulated this transaction on\",\n              \"type\": \"string\"\n            },\n            \"blockNumber\": {\n              \"description\": \"The block number the submitter simulated this transaction on\",\n              \"type\": \"number\"\n            },\n            \"blockTimestamp\": {\n              \"description\": \"The block unix timestamp of the simulated transaction\",\n              \"type\": \"number\"\n            }\n          },\n          \"required\": [\n            \"signature\",\n            \"signedByDelegate\",\n            \"signatureDeadline\",\n            \"typedData\",\n            \"blockHash\",\n            \"blockNumber\",\n            \"blockTimestamp\"\n          ]\n        }\n      },\n      \"required\": [\"thisPublication\"]\n    },\n    \"publicationId\": {\n      \"description\": \"The id of the publication, which is built up of the profileId + pubId + `DA` + first eight chars of the dataAvailabilityId (so it will always be unique)\",\n      \"type\": \"string\"\n    },\n    \"event\": {\n      \"type\": \"object\",\n      \"description\": \"This is trying to shape what you would get within an `EVM` event so you can easily parse it and understand it. This will always be identical to the EVM event data structure.\",\n      \"properties\": {\n        \"quoteParams\": {\n          \"type\": \"object\",\n          \"properties\": {\n            \"profileId\": {\n              \"type\": \"string\",\n              \"description\": \"The profileId which did the publication\"\n            },\n            \"contentURI\": {\n              \"type\": \"string\",\n              \"description\": \"The contentURI aka metadata for the publication\"\n            },\n            \"actionModules\": {\n              \"type\": \"array\",\n              \"description\": \"The array of action modules, for now this will always be empty\"\n            },\n            \"actionModulesInitDatas\": {\n              \"type\": \"array\",\n              \"description\": \"The array of action modules init data, for now this will always be empty\"\n            },\n            \"referenceModule\": {\n              \"type\": \"string\",\n              \"description\": \"The reference module, will always be address(0) for now\"\n            },\n            \"referenceModuleInitData\": {\n              \"type\": \"string\",\n              \"description\": \"The reference module init data, will always for now be empty byte\"\n            },\n            \"referrerProfileIds\": {\n              \"description\": \"The profile ids this publication references - will always be empty for now\",\n              \"type\": \"array\"\n            },\n            \"referrerPubIds\": {\n              \"description\": \"The pub ids this publication references - will always be empty for now\",\n              \"type\": \"array\"\n            },\n            \"pointedProfileId\": {\n              \"description\": \"The profile id of the quote is being made on\",\n              \"type\": \"string\"\n            },\n            \"pointedPubId\": {\n              \"description\": \"The pub ids this quote references - will always be empty for now\",\n              \"type\": \"string\"\n            }\n          },\n          \"required\": [\n            \"profileId\",\n            \"contentURI\",\n            \"actionModules\",\n            \"actionModulesInitDatas\",\n            \"referenceModule\",\n            \"referenceModuleInitData\",\n            \"referrerProfileIds\",\n            \"referrerPubIds\",\n            \"pointedProfileId\",\n            \"pointedPubId\"\n          ]\n        },\n        \"pubId\": {\n          \"type\": \"string\",\n          \"description\": \"The pubId for the publication\"\n        },\n        \"actionModulesInitReturnDatas\": {\n          \"type\": \"array\",\n          \"description\": \"The action modules init return datas, will always be empty for now\"\n        },\n        \"referenceModuleReturnData\": {\n          \"description\": \"The reference module return data, will always for now be empty byte\",\n          \"type\": \"string\"\n        },\n        \"referenceModuleInitReturnData\": {\n          \"type\": \"string\",\n          \"description\": \"The reference module init return data, will always for now be empty byte\"\n        },\n        \"transactionExecutor\": {\n          \"type\": \"string\",\n          \"description\": \"The address who executed transaction\"\n        },\n        \"timestamp\": {\n          \"description\": \"The timestamp date in milliseconds\",\n          \"type\": \"number\"\n        }\n      },\n      \"required\": [\n        \"quoteParams\",\n        \"pubId\",\n        \"actionModulesInitReturnDatas\",\n        \"referenceModuleReturnData\",\n        \"referenceModuleInitReturnData\",\n        \"transactionExecutor\",\n        \"timestamp\"\n      ]\n    }\n  },\n  \"required\": [\n    \"signature\",\n    \"dataAvailabilityId\",\n    \"type\",\n    \"timestampProofs\",\n    \"chainProofs\",\n    \"publicationId\",\n    \"event\"\n  ]\n}\n```\n\n## Technical code and how to run a verifier\n\nWe have 2 implementations of momoka one in node which supports browsers also and one in rust:\n\n- [momoka-node](./momoka-node/) - you can run the node verifier very easily and it also have indexer tools. Alongside this it has packages to run the verifier on the client side.\n- [momoka-rust](./momoka-rs/) - this is currently only supported lens v1 and will be migrated to lens v2 soon. Rust is the beta client verifier and eventually we like the rust client to be the main client.\n\n## Acknowledgements\n\n### Bundlr\n\nA special thank you to [Bundlr](https://bundlr.network/) for making this project possible with their cutting-edge technology. We are grateful to their exceptional team for their collaboration and support.\n\n### Arweave\n\nWe also extend our gratitude to [Arweave](https://www.arweave.org/) for providing decentralized storage solutions for our data, contributing to the overall success of the DA project.\n"
  },
  {
    "path": "momoka-node/.dockerignore",
    "content": ".dockerignore\nnpm-debug.log\nDockerfile\n.gitignore\njest.config.js\n.git\nnode_modules\n"
  },
  {
    "path": "momoka-node/.eslintrc.js",
    "content": "module.exports = {\n  env: {\n    es2021: true,\n    node: true,\n  },\n  ignorePatterns: ['.eslintrc.js', '*.json', '*.test.ts', '*.mock.ts'],\n  extends: [\n    'eslint:recommended',\n    'plugin:@typescript-eslint/recommended',\n    'plugin:import/recommended',\n    'plugin:import/typescript',\n    'plugin:prettier/recommended',\n  ],\n  parser: '@typescript-eslint/parser',\n  parserOptions: {\n    ecmaVersion: 12,\n    sourceType: 'module',\n  },\n  plugins: ['@typescript-eslint', 'prettier', 'prefer-arrow'],\n  settings: {\n    'import/resolver': {\n      typescript: true,\n      node: true,\n    },\n    'import/internal-regex': '^@lens/',\n  },\n  rules: {\n    '@typescript-eslint/comma-dangle': [\n      'error',\n      {\n        arrays: 'always-multiline',\n        objects: 'always-multiline',\n        imports: 'always-multiline',\n        exports: 'always-multiline',\n        enums: 'always-multiline',\n        functions: 'never',\n      },\n    ],\n    '@typescript-eslint/ban-types': [\n      'error',\n      { types: { Function: false, Boolean: false }, extendDefaults: true },\n    ],\n    '@typescript-eslint/explicit-function-return-type': ['error', { allowExpressions: true }],\n    '@typescript-eslint/no-empty-interface': ['warn'],\n    '@typescript-eslint/no-empty-function': 'warn',\n    '@typescript-eslint/no-explicit-any': ['warn'],\n    '@typescript-eslint/no-shadow': ['error'],\n    '@typescript-eslint/no-namespace': 'off',\n    '@typescript-eslint/no-non-null-assertion': 'off',\n    '@typescript-eslint/no-unused-vars': [\n      'warn',\n      {\n        argsIgnorePattern: '^_',\n      },\n    ],\n    '@typescript-eslint/no-var-requires': 'off',\n    '@typescript-eslint/ban-ts-comment': ['warn'],\n    // '@typescript-eslint/naming-convention': [\n    //   'error',\n    //   {\n    //     selector: 'default',\n    //     format: ['camelCase', 'PascalCase'],\n    //     leadingUnderscore: 'allow',\n    //   },\n    //   {\n    //     selector: 'typeProperty',\n    //     format: null,\n    //   },\n    //   {\n    //     selector: ['interface', 'typeLike'],\n    //     format: ['PascalCase'],\n    //   },\n    //   {\n    //     selector: 'variable',\n    //     modifiers: ['const'],\n    //     format: ['camelCase', 'UPPER_CASE'],\n    //     leadingUnderscore: 'allow',\n    //   },\n    //   {\n    //     selector: 'enumMember',\n    //     format: ['UPPER_CASE'],\n    //   },\n    // ],\n    'require-await': ['error'],\n    'capitalized-comments': 'off',\n    'no-control-regex': 'off',\n    'no-empty': 'warn',\n    'no-shadow': 'off',\n    'prefer-arrow/prefer-arrow-functions': [\n      'warn',\n      {\n        disallowPrototype: true,\n        singleReturnOnly: false,\n        classPropertiesAllowed: false,\n      },\n    ],\n    // 'array-element-newline': ['error', 'consistent'],\n    'arrow-body-style': 'off',\n    // 'max-len': [\n    //   'error',\n    //   {\n    //     code: 120,\n    //     ignoreComments: true,\n    //     ignorePattern: '^import .*$',\n    //     ignoreStrings: true,\n    //     ignoreTemplateLiterals: true,\n    //     ignoreRegExpLiterals: true,\n    //   },\n    // ],\n    'max-statements-per-line': 'error',\n    'no-case-declarations': 'off',\n    'no-constant-condition': 'warn',\n  },\n};\n"
  },
  {
    "path": "momoka-node/.nvmrc",
    "content": "v18.12.1\n"
  },
  {
    "path": "momoka-node/.prettierignore",
    "content": "*.yml\n*.yaml\n*.md\n"
  },
  {
    "path": "momoka-node/.prettierrc",
    "content": "{\n  \"printWidth\": 100,\n  \"singleQuote\": true,\n  \"trailingComma\": \"es5\"\n}\n"
  },
  {
    "path": "momoka-node/CHANGELOG.md",
    "content": "# unreleased - fill in any changes you do here!\n\n## Features\n\n## Bug fixes\n\n## Breaking changes\n\n###################################################################\n\n# 2.0.0 - 18th December 2023\n\n# Features\n\n- feat: add support for lens v2 publications\n- fix: export MomokaProvider and MomokaActionTypes\n\n# 1.1.2 - 24th May 2023\n\n## Bug fixes\n\n- fix: uninstall lib-curl\n\n# 1.1.1 - 24th May 2023\n\n# Bug fixes\n\n- fix: remove lib-curl and use axios instead on node server to avoid some OS issues\n\n# 1.0.0>1.1.0 - 26th April 2023\n\n## Features\n\n- feat: Initial release 1.0.0\n\n## Fix\n\n- fix: Avoid installing `only-allow` during `preinstall` step\n"
  },
  {
    "path": "momoka-node/Dockerfile",
    "content": "FROM mcr.microsoft.com/devcontainers/typescript-node:18 as base\n\nWORKDIR /usr/src/app\n\nCOPY package*.json ./\nCOPY tsconfig.json ./\nCOPY src ./src\nCOPY .env ./\n\n# Enable corepack which would install correct version of pnpm\nRUN corepack enable\n\n# Install project dependencies using pnpm\nRUN npx pnpm install\n\nRUN chown -R node:node /usr/src/app\n\nUSER node\n\n# Build the project\nRUN npm run build\n\nEXPOSE 3008\n\nCMD [\"npm\", \"run\", \"start\"]\n"
  },
  {
    "path": "momoka-node/Dockerfile.stable",
    "content": "FROM node:18-alpine AS base\r\n\r\n# Install pnpm through corepack\r\nRUN apk update\r\nRUN apk add --no-cache libc6-compat\r\nRUN corepack enable\r\nRUN corepack prepare pnpm@latest --activate\r\n\r\n# Specify a path for pnpm global root\r\nENV PNPM_HOME=/usr/local/bin\r\n\r\nFROM base as runtime\r\n\r\n# Install stable version of momoka\r\nRUN pnpm add -g @lens-protocol/momoka\r\n\r\n# Run using the default shell, this is important to infer the environment variables\r\nCMD [\"sh\", \"-c\", \"momoka --node $NODE_URL --environment=$ENVIRONMENT --concurrency=$CONCURRENCY --fromHead=true\"]"
  },
  {
    "path": "momoka-node/LICENSE.txt",
    "content": "Copyright (c) 2023 Aave companies\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE."
  },
  {
    "path": "momoka-node/README.md",
    "content": "# Momoke-node\n\nThis package holds the node implementation of the momoka and also the ability to run it client side.\n\n## Running\n\n### Key information\n\nTo run the verifier, you MUST use an archive node. You can sign up with Alchemy and use one of their free nodes. Non-archive nodes do not retain state information beyond the previous 16-128 blocks. While this may be sufficient for immediate runtime calls after the DA publication is created, it will not work for past transactions beyond the 16-128 block range.\n\n### Being as fast as possible - Concurrency\n\nThe verifier is designed for optimal speed, with performance determined by its configuration parameters. Achieving 10,000 TPS is not a problem, provided that the hardware and nodes can support these limits. When running the verifier, you have the option to set the CONCURRENCY, which divides the number of requests sent to the NODE_URL simultaneously. Higher concurrency values result in faster performance during resynchronization or when handling a large volume of transactions at once.\n\nThe default concurrency is 100, which typically requires a paid archive node. If you prefer using a free node, the verifier will be slower, but it will still work effectively. For a free node, you can set the concurrency between 1 and 3. For example, at LENS, we have set the concurrency at 120, which enables our verifier to run very quickly.\n\n## Running straight out the box\n\nCurrently, you have two options to run it directly. Either by using the npm `momoka` package, or through Docker.\n\n### Running from npm\n\nYou can install it globally:\n\n```bash\n$ npm i @lens-protocol/momoka -g\n```\n\nthen you can just run:\n\n```bash\n$ momoka --node 'YOUR_NODE' --environment='MUMBAI|AMOY|POLYGON' --concurrency=20\n```\n\nyou can also just run with npx:\n\n```bash\n$ npx @lens-protocol/momoka --node 'YOUR_NODE' --environment='MUMBAI|AMOY|POLYGON' --concurrency=20\n```\n\nBy default it will not resync all the data, it just start verifying from this point onwards unless you add the parameter `--resync=true` which will start from block 0 and resync all the data.\n\n### Running from Docker\n\nYou can use the `Dockerfile.stable` file to set up a container which will run the latest stable release on Momoka from `npm`. The Dockerfile assumes running on the `POLYGON` environment, and sets concurrency to 100. You can change those if necessary.\n\nA few environment variables are required for it to work, which you can set however you'd like depending on how and where you're running the Docker container. Specifically, you need to set `NODE_URL`, `ENVIRONMENT`, and `CONCURRENCY` environment variables.\n\n> NOTE: A `render.yaml` IaC blueprint is also provided which runs `Dockerfile.stable`. If you'd like to use [Render](https://render.com) for hosting your Momoka verifier, you can easily deploy it there by using the Render Blueprint. See their docs on [Infrastructure as Code](https://render.com/docs/infrastructure-as-code) to see how.\n\n### Parameter meanings\n\n- `--node` - this is the URI of the Polygon archive node you wish to connect to, this can be a free node or a paid node, it is recommended to use a paid node for the best performance. you can get up and running with a node using Alchemy, Infura, or any other similar infrastructure provider\n- `--environment` - this is the environment you wish to run the verifier on, this can be `MUMBAI` `AMOY` or `POLYGON`\n- `--concurrency` - this is the concurrency you wish to run the verifier on, which was talked in depth above\n- `--resync` - this is a boolean value, which if set to true will start the verifier from the block 0 and resync all transactions from the past, if set to false it will start verifying from this moment onwards.\n\n## Installing package\n\nThis is a written in node, and this means it can be run on the client as well as a server; it won't use the DB on the client but can mean you can run proof checks in runtime, which is super powerful. Also, you may which to monitor this on your server to index stuff as it comes in.\n\n```bash\n$ npm i @lens-protocol/momoka\n```\n\n<b>Do not use if you do not know what you are doing the basic config works for all production apps</b>\n\nPlease note if you wish to use a different deployment then `PRODUCTION` you will need to make sure you put `deployment: STAGING` or `deployment: LOCAL` in the `EthereumNode` object. This for most will not be the case.\n\n### Client usage\n\nThe package exposes a separate entry point for the client usage (`'@lens-protocol/momoka/client'`) to make sure the bundle size is not affected by any polyfills or other node specific code.\n\nCheck the `playground-browser` folder for a working example of the client usage.\n\n#### checkDAProof\n\nThe `checkDAProof` will return you a failure reason of the enum `MomokaValidatorError`, and if successful, you be returned the entire `DAStructurePublication`. This is a client specific version of the `checkDAProof` function that doesn't have any caching in place. For the server version, please see the server usage section.\n\n```ts\nimport { checkDAProof, EthereumNode, Environment } from '@lens-protocol/momoka/client';\n\nconst ethereumNode: EthereumNode = {\n  environment: Environment.POLYGON,\n  nodeUrl: YOUR_NODE_URL,\n};\n\nconst result = await checkDAProof(PROOF_ID, ethereumNode);\nif (result.isSuccess()) {\n  console.log('proof valid', result.successResult);\n  return; // all is well!\n}\n\n// it failed!\nconsole.error('proof invalid do something', result.failure);\n```\n\n### Server usage\n\n#### checkDAProof\n\nThe `checkDAProof` will return you a failure reason of the enum `MomokaValidatorError`, and if successful, you be returned the entire `DAStructurePublication`. This is a server specific version of the `checkDAProof` function that has caching in place. For the client version, please see the client usage section.\n\n```ts\nimport { checkDAProof, EthereumNode, Environment } from '@lens-protocol/momoka';\n\nconst ethereumNode: EthereumNode = {\n  environment: Environment.POLYGON,\n  nodeUrl: YOUR_NODE_URL,\n};\n\nconst result = await checkDAProof(PROOF_ID, ethereumNode);\nif (result.isSuccess()) {\n  console.log('proof valid', result.successResult);\n  return; // all is well!\n}\n\n// it failed!\nconsole.error('proof invalid do something', result.failure);\n```\n\n#### startDAVerifierNode\n\nThis will start watching all the DA items coming in and logging it all out in your terminal. you can install the package and run it on your own server. By default it will not resync all the data, it just start verifying from this point onwards unless you add the parameter which is defined below.\n\n```ts\nimport { startDAVerifierNode, EthereumNode } from '@lens-protocol/momoka';\n\nconst ethereumNode: EthereumNode = {\n  environment: Environment.POLYGON,\n  nodeUrl: YOUR_NODE_URL,\n};\n\n// you should read up on section \"Being as fast as possible - Concurrency\"\nconst concurrency = 100;\n\n// it run forever and log out to the terminal\nstartDAVerifierNode(ethereumNode, concurrency);\n```\n\n#### startDAVerifierNode - Stream with proofs verified\n\nIf you wish to index the data yourself, you can use the `startDAVerifierNode` and stream the data out to your own DB using the `StreamCallback`. This will run the verifier node and check the proofs as every new one comes in. By default it will not resync all the data, it just start verifying from this point onwards unless you add the parameter which is defined below.\n\n```ts\nimport { startDAVerifierNode, StreamResult, EthereumNode } from '@lens-protocol/momoka';\n\nconst stream = (result: StreamResult) => {\n  console.log('streamed publication', result);\n\n  if (result.success) {\n    // success - insert into your db here if you wish\n    console.log('success', result.dataAvailabilityResult);\n  } else {\n    // failure reason\n    console.log('reason', result.failureReason);\n    // this will expose the submisson if it could be read\n    console.log('submisson', result.dataAvailabilityResult);\n  }\n};\n\nconst ethereumNode: EthereumNode = {\n  environment: Environment.POLYGON,\n  nodeUrl: YOUR_NODE_URL,\n};\n\n// you should read up on section \"Being as fast as possible - Concurrency\"\nconst concurrency = 100;\n\n// it run forever and log out to the terminal\nstartDAVerifierNode(ethereumNode, concurrency, { stream });\n```\n\n#### Start verifier from block 0\n\nYou may wish to start the verifier and recheck from the first ever momoka transaction, You can do this by passing in the `resync` option.\n\n```ts\nimport { startDAVerifierNode, StreamResult, EthereumNode } from '@lens-protocol/momoka';\n\nconst ethereumNode: EthereumNode = {\n  environment: Environment.POLYGON,\n  nodeUrl: YOUR_NODE_URL,\n};\n\n// you should read up on section \"Being as fast as possible - Concurrency\"\nconst concurrency = 100;\n\n// it run forever and log out to the terminal\nstartDAVerifierNode(ethereumNode, concurrency, { resync: true });\n```\n\n#### startDATrustingIndexing\n\nIf you just want to get the data as fast as possible and do not wish to verify the proofs, you can use the `startDATrustingIndexing` function. This will stream out the data as fast as possible and will not check the proofs, so does not require an archive node.\n\n```ts\nimport {\n  startDATrustingIndexing,\n  StreamResult,\n  StartDATrustingIndexingRequest,\n} from '@lens-protocol/momoka';\n\nconst stream = (result: StreamResult) => {\n  console.log('streamed publication', result);\n\n  if (result.success) {\n    // success - insert into your db here if you wish\n    console.log('success', result.dataAvailabilityResult);\n  } else {\n    // failure reason\n    console.log('reason', result.failureReason);\n    // this will expose the submisson if it could be read\n    console.log('submisson', result.dataAvailabilityResult);\n  }\n};\n\nconst request: StartDATrustingIndexingRequest = {\n  environment: Environment.POLYGON,\n  stream,\n};\n\n// it run forever and stream data as it comes in\nstartDATrustingIndexing(request);\n```\n\n### Running from this repo\n\n#### Dependencies\n\nThis package has a few dependencies that need to be installed, these are:\n\n- we use `pnpm` for this repo so please have it installed: https://pnpm.io/installation\n- nvm is also used for node versioning:\n\nIf you wish to just run it on its own, you can just run:\n\n```bash\n$ nvm use\n$ pnpm i\n$ pnpm run start\n```\n\nTo build its just:\n\n```bash\n$ pnpm build\n```\n\n### Tests\n\nTo run the tests:\n\ncreate an `.env.test` file with the following (you need to add a AMOY node url)\n\n```bash\nETHEREUM_NETWORK=AMOY\nNODE_URL=AMOY_NODE_URL\nDEPLOYMENT=PRODUCTION\nCONCURRENCY=10\n```\n\n```bash\n$ pnpm test\n```\n\n### Docker\n\nPlease note you need a `.env` setup for this to work.\n\nTo run the docker first build it:\n\n```bash\n$ docker build -t da-service .\n```\n\nThen run it:\n\n```bash\n$ docker run -d -p 3008:3008 da-service\n```\n\nThis will return an docker id.\n\nThen to listen to the logs you can:\n\n```bash\ndocker logs <id>\n```\n\n## Validation checks flows\n\nThis is written in sudo `node` code to understand the current flow of the validation checks.\n\n```ts\nasync function validateClaim() {\n  // 1. Fetch DA metadata from Bundlr\n  const metadata = await fetchMetadataFromBundlr();\n\n  // 2. Check if `signature` is defined\n  if (!signature) {\n    return MomokaValidatorError.NO_SIGNATURE_SUBMITTER;\n  }\n\n  // 3. Verify `signature` with `metadata`\n  if (!verifySignature(signature, metadata)) {\n    return MomokaValidatorError.INVALID_SIGNATURE_SUBMITTER;\n  }\n\n  // 4. Check timestamp proofs with Bundlr\n  if (!(await checkTimestampProofs())) {\n    return MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SIGNATURE;\n  }\n\n  // 5. Check if timestamp proofs submitter is valid\n  if (!isValidTimestampProofsSubmitter()) {\n    return MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SUBMITTER;\n  }\n\n  // 6. Check if event `timestamp` equals `blockTimestamp`\n  if (eventTimestamp !== blockTimestamp) {\n    return MomokaValidatorError.INVALID_EVENT_TIMESTAMP;\n  }\n\n  // 7. Check if block number is closest to timestamp proofs\n  if (!isClosestBlock()) {\n    return MomokaValidatorError.NOT_CLOSEST_BLOCK;\n  }\n\n  // 8. Check if chain signature has already been used\n  if (!chainSignatureAlreadyUsed()) {\n    return MomokaValidatorError.CHAIN_SIGNATURE_ALREADY_USED;\n  }\n\n  // 9. Check if pointer is defined\n  if (isPost() && pointer) {\n    return MomokaValidatorError.INVALID_POINTER_SET_NOT_NEEDED;\n  } else if (!pointer && (isMirror() || isComment())) {\n    return MomokaValidatorError.INVALID_POINTER_NOT_SET;\n  }\n\n  // 9.1. Check pointer type (if defined)\n  if (pointer && !isPointerTypeOnDA()) {\n    return PUBLICATION_NONE_DA;\n  }\n\n  // 10. Verify pointer (if defined) - follow steps from 1\n  const pointerStepError = await verifyPointer();\n  if (pointerStepError) {\n    return pointerStepError;\n  }\n\n  // 11. Check if formatted typed data is valid\n  if (!isValidFormattedTypedData()) {\n    return MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA;\n  }\n\n  // 12a. If `POST`, simulate transaction using eth_call\n  if (isPost()) {\n    const simulationResult = await simulateTransaction();\n    if (simulationResult === 'nodeError') {\n      return MomokaValidatorError.SIMULATION_NODE_COULD_NOT_RUN;\n    } else if (simulationResult === 'failed') {\n      return MomokaValidatorError.SIMULATION_FAILED;\n    }\n  }\n  // 12b. If `COMMENT` or `MIRROR`, perform additional checks\n  else {\n    if (!isValidPublicationNonce()) {\n      return MomokaValidatorError.PUBLICATION_NONCE_INVALID;\n    }\n    if (!isPublicationSignerAllowed()) {\n      return MomokaValidatorError.PUBLICATION_SIGNER_NOT_ALLOWED;\n    }\n  }\n\n  // 13. Cross-check typed data values with `event`\n  if (!isEventMatchingTypedData()) {\n    return MomokaValidatorError.EVENT_MISMATCH;\n  }\n\n  // 14. Check if `publicationId` matches expected ID\n  if (!isPublicationIdMatch()) {\n    // 15. Check if it could of been a potential reorg\n\n    // if so:\n    return MomokaValidatorError.POTENTIAL_REORG;\n\n    // if not\n    return MomokaValidatorError.GENERATED_PUBLICATION_ID_MISMATCH;\n  }\n\n  // all validated!\n}\n```\n\nAt this point, you have done all the checks needed, and this is a valid submission! As you see, using signatures and EVM calls, we can verify the data is correct and the submitter is correct without any other third party.\n\n### Validation error checks types and messages\n\nThe summary in the code should explain what is being checked for and what it would fail out if it doesn't match. Below is the full list of error cases\n\n```ts\nexport enum MomokaValidatorError {\n  /**\n   * This means the main signature has not been attached to the payload\n   */\n  NO_SIGNATURE_SUBMITTER = 'NO_SIGNATURE_SUBMITTER',\n\n  /**\n   * This means the main signature has not been signed by the same payload as the data itself\n   */\n  INVALID_SIGNATURE_SUBMITTER = 'INVALID_SIGNATURE_SUBMITTER',\n\n  /**\n   * This means the submitted timestamp proof does not have a valid timestamp proof signature\n   */\n  TIMESTAMP_PROOF_INVALID_SIGNATURE = 'TIMESTAMP_PROOF_INVALID_SIGNATURE',\n\n  /**\n   * This means the type in the timestamp proofs do not match\n   * timestamp proofs are not portable\n   */\n  TIMESTAMP_PROOF_INVALID_TYPE = 'TIMESTAMP_PROOF_INVALID_TYPE',\n\n  /**\n   * This means the da id in the timestamp proofs do not match up\n   * timestamp proofs are not portable\n   */\n  TIMESTAMP_PROOF_INVALID_DA_ID = 'TIMESTAMP_PROOF_INVALID_DA_ID',\n\n  /**\n   * This means the timestamp proof uploaded was not done by a valid submitter\n   */\n  TIMESTAMP_PROOF_NOT_SUBMITTER = 'TIMESTAMP_PROOF_NOT_SUBMITTER',\n\n  /**\n   * We tried to call them 5 times and its errored out - this is not a bad proof but bundlr/arweave are having issues\n   */\n  CAN_NOT_CONNECT_TO_BUNDLR = 'CAN_NOT_CONNECT_TO_BUNDLR',\n\n  /**\n   * The DA tx could not be found or invalid on the bundlr/arweave nodes\n   * can happened if pasted it in wrong\n   */\n  INVALID_TX_ID = 'INVALID_TX_ID',\n\n  /**\n   * This the typed data format is invalid (aka a invalid address type etc)\n   */\n  INVALID_FORMATTED_TYPED_DATA = 'INVALID_FORMATTED_TYPED_DATA',\n\n  /**\n   * This means it can not read the block from the node\n   */\n  BLOCK_CANT_BE_READ_FROM_NODE = 'BLOCK_CANT_BE_READ_FROM_NODE',\n\n  /**\n   * This means it can not read the data from the node\n   */\n  DATA_CANT_BE_READ_FROM_NODE = 'DATA_CANT_BE_READ_FROM_NODE',\n\n  /**\n   * This means the simulation was not able to be ran on the node, this does not mean\n   * that it would fail on chain, it means the nodes may of been down and needs rechecking\n   */\n  SIMULATION_NODE_COULD_NOT_RUN = 'SIMULATION_NODE_COULD_NOT_RUN',\n\n  /**\n   * This means the simulation was not successful and got rejected on-chain\n   * or the result from the simulation did not match the expected result\n   */\n  SIMULATION_FAILED = 'SIMULATION_FAILED',\n\n  /**\n   * This means the event emitted from the simulation does not match the expected event\n   */\n  EVENT_MISMATCH = 'EVENT_MISMATCH',\n\n  /**\n   * This means the event timestamp passed into the emitted event does not match the signature timestamp\n   */\n  INVALID_EVENT_TIMESTAMP = 'INVALID_EVENT_TIMESTAMP',\n\n  /**\n   * This means the deadline set in the typed data is not correct\n   */\n  INVALID_TYPED_DATA_DEADLINE_TIMESTAMP = 'INVALID_TYPED_DATA_DEADLINE_TIMESTAMP',\n\n  /**\n   * This means the generated publication id for the generic id does not match\n   * what it should be\n   */\n  GENERATED_PUBLICATION_ID_MISMATCH = 'GENERATED_PUBLICATION_ID_MISMATCH',\n\n  /**\n   * This means the pointer set in the chain proofs is not required but set anyway\n   */\n  INVALID_POINTER_SET_NOT_NEEDED = 'INVALID_POINTER_SET_NOT_NEEDED',\n\n  /**\n   * This means the pointer has failed verification\n   */\n  POINTER_FAILED_VERIFICATION = 'POINTER_FAILED_VERIFICATION',\n\n  /**\n   * This means the block processed against is not the closest block to the timestamp proofs\n   */\n  NOT_CLOSEST_BLOCK = 'NOT_CLOSEST_BLOCK',\n\n  /**\n   * This means the timestamp proofs are not close enough to the block\n   */\n  BLOCK_TOO_FAR = 'NOT_CLOSEST_BLOCK',\n\n  /**\n   * This means the publication submitted does not have a valid pointer\n   * and a pointer is required\n   */\n  PUBLICATION_NO_POINTER = 'PUBLICATION_NO_POINTER',\n\n  /**\n   * Some publications (comment and mirror) for now can only be on another\n   * DA publication not on evm chain publications\n   */\n  PUBLICATION_NONE_DA = 'PUBLICATION_NONE_DA',\n\n  /**\n   * This means the publication nonce is invalid at the time of submission\n   */\n  PUBLICATION_NONCE_INVALID = 'PUBLICATION_NONCE_INVALID',\n\n  /**\n   * This means the publication submisson was signed by a wallet that is not allowed\n   */\n  PUBLICATION_SIGNER_NOT_ALLOWED = 'PUBLICATION_SIGNER_NOT_ALLOWED',\n\n  /**\n   * This means the evm signature has already been used\n   */\n  CHAIN_SIGNATURE_ALREADY_USED = 'CHAIN_SIGNATURE_ALREADY_USED',\n\n  /**\n   * This means the publication submisson could not pass potentional due to a reorg\n   */\n  POTENTIAL_REORG = 'POTENTIAL_REORG',\n\n  /**\n   * unknown error should not happen but catch all\n   */\n  UNKNOWN = 'UNKNOWN',\n}\n```\n\n## Contributing\n\nAny PRs are welcome and we will review them as soon as possible. Please make sure you have tests and they pass.\n\n## Acknowledgements\n\n### Bundlr\n\nA special thank you to [Bundlr](https://bundlr.network/) for making this project possible with their cutting-edge technology. We are grateful to their exceptional team for their collaboration and support.\n\n### Arweave\n\nWe also extend our gratitude to [Arweave](https://www.arweave.org/) for providing decentralized storage solutions for our data, contributing to the overall success of the DA project.\n\n## Why node?\n\nOur goal was to create a tool that could be verified both on the client and server side, and we found that Node.js was the most suitable option for this purpose. Additionally, we aimed to make it as understandable as possible, and Node.js is renowned for its ease of use and a big languaged used throughout web3 development. As per our roadmap, we plan to migrate a significant portion of this stack to Rust, a more low-level language, to achieve maximum speed once we need it.\n"
  },
  {
    "path": "momoka-node/client/package.json",
    "content": "{\n  \"main\": \"../lib/client/index.js\"\n}\n"
  },
  {
    "path": "momoka-node/codegen.yaml",
    "content": "schema: https://lens.bundlr.network/graphql\ndocuments: './src/graphql/*.graphql'\ngenerates:\n  ./src/graphql/generated.ts:\n    plugins:\n      - typescript\n      - typescript-operations\n      - typed-document-node\n    config:\n      fetcher: fetch"
  },
  {
    "path": "momoka-node/jest.config.js",
    "content": "/** @type {import('ts-jest').JestConfigWithTsJest} */\nmodule.exports = {\n  preset: 'ts-jest',\n  testEnvironment: 'node',\n  collectCoverage: true,\n  coverageDirectory: 'coverage',\n  setupFiles: ['<rootDir>/src/__TESTS__/config/jest.setup.js'],\n  coveragePathIgnorePatterns: [\n    'node_modules',\n    '<rootDir>/src/__TESTS__',\n    '.mock.ts',\n    '<rootDir>/src/logger.ts',\n    '<rootDir>/src/arweave',\n    '<rootDir>/src/bundlr',\n  ],\n  testPathIgnorePatterns: ['/node_modules/', '/lib/', '/playground-browser/'],\n  verbose: true,\n};\n"
  },
  {
    "path": "momoka-node/package.json",
    "content": "{\n  \"name\": \"@lens-protocol/momoka\",\n  \"version\": \"2.1.1\",\n  \"description\": \"Momoka node for the Lens protocol\",\n  \"main\": \"lib/index.js\",\n  \"types\": \"./lib/index.d.ts\",\n  \"exports\": {\n    \".\": \"./lib/index.js\",\n    \"./client\": \"./lib/client/index.js\",\n    \"./package.json\": \"./package.json\"\n  },\n  \"files\": [\n    \"lib/**/*\",\n    \"client/**/*\",\n    \"images/**/*\",\n    \"README.md\"\n  ],\n  \"scripts\": {\n    \"build\": \"tsc\",\n    \"build:watch\": \"tsc --watch\",\n    \"eslint:fix\": \"eslint \\\"src/**/*.ts\\\" --quiet --fix\",\n    \"eslint\": \"eslint \\\"src/**/*.ts\\\" --quiet\",\n    \"start:fork\": \"REQ_TIMEOUT=100000 anvil --fork-url NODE_URL --silent\",\n    \"start\": \"env-cmd -f .env node lib/runnable/da-verifier-node.runnable.js\",\n    \"start:failed\": \"env-cmd -f .env ts-node src/failed-submissons.runnable.ts\",\n    \"debug:playground\": \"npm run build && env-cmd -f .env node lib/__PLAYGROUND__/index.js\",\n    \"generate\": \"graphql-codegen\",\n    \"test\": \"npm run build && env-cmd -f .env.test jest\",\n    \"lint\": \"pnpm run prettier && pnpm run tsc\",\n    \"lint:fix\": \"pnpm run prettier:fix && pnpm run eslint\",\n    \"prettier:fix\": \"prettier --write .\",\n    \"prettier\": \"prettier --check .\",\n    \"tsc\": \"tsc --noEmit\",\n    \"prepublishOnly\": \"pnpm run build\",\n    \"publish\": \"pnpm publish --access public\"\n  },\n  \"devDependencies\": {\n    \"@graphql-codegen/cli\": \"2.11.3\",\n    \"@graphql-codegen/typed-document-node\": \"2.3.2\",\n    \"@graphql-codegen/typescript\": \"2.7.2\",\n    \"@graphql-codegen/typescript-operations\": \"2.5.2\",\n    \"@types/bluebird\": \"^3.5.38\",\n    \"@types/jest\": \"^29.2.6\",\n    \"@types/yargs\": \"^17.0.22\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.49.0\",\n    \"@typescript-eslint/parser\": \"^5.49.0\",\n    \"env-cmd\": \"^10.1.0\",\n    \"eslint\": \"^7.28.0\",\n    \"eslint-config-prettier\": \"^8.5.0\",\n    \"eslint-import-resolver-typescript\": \"^3.5.3\",\n    \"eslint-plugin-import\": \"npm:eslint-plugin-i@^2.26.0-2\",\n    \"eslint-plugin-prefer-arrow\": \"^1.2.3\",\n    \"eslint-plugin-prettier\": \"^3.4.0\",\n    \"ethereum-abi-types-generator\": \"^1.3.2\",\n    \"graphql-codegen\": \"^0.4.0\",\n    \"jest\": \"^29.4.0\",\n    \"ts-jest\": \"^29.0.5\",\n    \"ts-node\": \"10.9.1\",\n    \"typescript\": \"^4.6.4\"\n  },\n  \"dependencies\": {\n    \"@ethersproject/abstract-provider\": \"^5.7.0\",\n    \"@ethersproject/bytes\": \"^5.7.0\",\n    \"@graphql-typed-document-node/core\": \"^3.1.2\",\n    \"@urql/core\": \"^3.0.5\",\n    \"arweave\": \"^1.13.3\",\n    \"axios\": \"^1.3.4\",\n    \"bluebird\": \"^3.7.2\",\n    \"ethereum-multicall\": \"^2.24.0\",\n    \"ethers\": \"^5.7.2\",\n    \"graphql\": \"^16.6.0\",\n    \"level\": \"^8.0.0\",\n    \"yargs\": \"^17.7.1\"\n  },\n  \"license\": \"MIT\",\n  \"bin\": {\n    \"momoka\": \"./lib/bin/cli.js\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/lens-protocol/momoka.git\"\n  },\n  \"packageManager\": \"pnpm@8.4.0\"\n}\n"
  },
  {
    "path": "momoka-node/playground-browser/.gitignore",
    "content": "# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.\n\n# dependencies\n/node_modules\n/.pnp\n.pnp.js\n\n# testing\n/coverage\n\n# production\n/build\n\n# misc\n.DS_Store\n.env.local\n.env.development.local\n.env.test.local\n.env.production.local\n\nnpm-debug.log*\nyarn-debug.log*\nyarn-error.log*\n"
  },
  {
    "path": "momoka-node/playground-browser/README.md",
    "content": "# Getting Started with Create React App\n\nThis project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app).\n\n## Available Scripts\n\nIn the project directory, you can run:\n\n### `npm start`\n\nRuns the app in the development mode.\\\nOpen [http://localhost:3000](http://localhost:3000) to view it in the browser.\n\nThe page will reload if you make edits.\\\nYou will also see any lint errors in the console.\n\n### `npm test`\n\nLaunches the test runner in the interactive watch mode.\\\nSee the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information.\n\n### `npm run build`\n\nBuilds the app for production to the `build` folder.\\\nIt correctly bundles React in production mode and optimizes the build for the best performance.\n\nThe build is minified and the filenames include the hashes.\\\nYour app is ready to be deployed!\n\nSee the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information.\n\n### `npm run eject`\n\n**Note: this is a one-way operation. Once you `eject`, you can’t go back!**\n\nIf you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.\n\nInstead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.\n\nYou don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.\n\n## Learn More\n\nYou can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started).\n\nTo learn React, check out the [React documentation](https://reactjs.org/).\n"
  },
  {
    "path": "momoka-node/playground-browser/config-overrides.js",
    "content": "module.exports = function override(config) {\n  // required to support .cjs extension which is used by axios inside the verifier library\n  // see https://github.com/facebook/create-react-app/pull/12021\n  // TODO: Build verifier client as a ES module\n  config.module.rules = config.module.rules.map((rule) => {\n    if (rule.oneOf instanceof Array) {\n      rule.oneOf[rule.oneOf.length - 1].exclude = [\n        /\\.(js|mjs|jsx|cjs|ts|tsx)$/,\n        /\\.html$/,\n        /\\.json$/,\n      ];\n    }\n    return rule;\n  });\n\n  return config;\n};\n"
  },
  {
    "path": "momoka-node/playground-browser/package.json",
    "content": "{\n  \"name\": \"playground-browser\",\n  \"version\": \"0.1.0\",\n  \"private\": true,\n  \"dependencies\": {\n    \"@testing-library/jest-dom\": \"^5.16.5\",\n    \"@testing-library/react\": \"^13.4.0\",\n    \"@testing-library/user-event\": \"^13.5.0\",\n    \"@types/jest\": \"^27.5.2\",\n    \"@types/node\": \"^16.18.16\",\n    \"@types/react\": \"^18.0.28\",\n    \"@types/react-dom\": \"^18.0.11\",\n    \"react\": \"^18.2.0\",\n    \"react-dom\": \"^18.2.0\",\n    \"react-scripts\": \"5.0.1\",\n    \"typescript\": \"^4.9.5\",\n    \"web-vitals\": \"^2.1.4\"\n  },\n  \"devDependencies\": {\n    \"react-app-rewired\": \"^2.2.1\"\n  },\n  \"scripts\": {\n    \"start\": \"react-app-rewired start\",\n    \"build\": \"react-app-rewired build\",\n    \"test\": \"react-app-rewired test\",\n    \"eject\": \"react-scripts eject\"\n  },\n  \"eslintConfig\": {\n    \"extends\": [\n      \"react-app\",\n      \"react-app/jest\"\n    ]\n  },\n  \"browserslist\": {\n    \"production\": [\n      \">0.2%\",\n      \"not dead\",\n      \"not op_mini all\"\n    ],\n    \"development\": [\n      \"last 1 chrome version\",\n      \"last 1 firefox version\",\n      \"last 1 safari version\"\n    ]\n  }\n}\n"
  },
  {
    "path": "momoka-node/playground-browser/public/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\" />\n    <link rel=\"icon\" href=\"%PUBLIC_URL%/favicon.ico\" />\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\" />\n    <meta name=\"theme-color\" content=\"#000000\" />\n    <meta name=\"description\" content=\"Web site created using create-react-app\" />\n    <link rel=\"apple-touch-icon\" href=\"%PUBLIC_URL%/logo192.png\" />\n    <!--\n      manifest.json provides metadata used when your web app is installed on a\n      user's mobile device or desktop. See https://developers.google.com/web/fundamentals/web-app-manifest/\n    -->\n    <link rel=\"manifest\" href=\"%PUBLIC_URL%/manifest.json\" />\n    <!--\n      Notice the use of %PUBLIC_URL% in the tags above.\n      It will be replaced with the URL of the `public` folder during the build.\n      Only files inside the `public` folder can be referenced from the HTML.\n\n      Unlike \"/favicon.ico\" or \"favicon.ico\", \"%PUBLIC_URL%/favicon.ico\" will\n      work correctly both with client-side routing and a non-root public URL.\n      Learn how to configure a non-root public URL by running `npm run build`.\n    -->\n    <title>React App</title>\n  </head>\n  <body>\n    <noscript>You need to enable JavaScript to run this app.</noscript>\n    <div id=\"root\"></div>\n    <!--\n      This HTML file is a template.\n      If you open it directly in the browser, you will see an empty page.\n\n      You can add webfonts, meta tags, or analytics to this file.\n      The build step will place the bundled scripts into the <body> tag.\n\n      To begin the development, run `npm start` or `yarn start`.\n      To create a production bundle, use `npm run build` or `yarn build`.\n    -->\n  </body>\n</html>\n"
  },
  {
    "path": "momoka-node/playground-browser/public/manifest.json",
    "content": "{\n  \"short_name\": \"React App\",\n  \"name\": \"Create React App Sample\",\n  \"icons\": [\n    {\n      \"src\": \"favicon.ico\",\n      \"sizes\": \"64x64 32x32 24x24 16x16\",\n      \"type\": \"image/x-icon\"\n    },\n    {\n      \"src\": \"logo192.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"192x192\"\n    },\n    {\n      \"src\": \"logo512.png\",\n      \"type\": \"image/png\",\n      \"sizes\": \"512x512\"\n    }\n  ],\n  \"start_url\": \".\",\n  \"display\": \"standalone\",\n  \"theme_color\": \"#000000\",\n  \"background_color\": \"#ffffff\"\n}\n"
  },
  {
    "path": "momoka-node/playground-browser/public/robots.txt",
    "content": "# https://www.robotstxt.org/robotstxt.html\nUser-agent: *\nDisallow:\n"
  },
  {
    "path": "momoka-node/playground-browser/src/App.css",
    "content": ".App {\n  text-align: center;\n}\n\n.App-logo {\n  height: 40vmin;\n  pointer-events: none;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n  .App-logo {\n    animation: App-logo-spin infinite 20s linear;\n  }\n}\n\n.App-header {\n  background-color: #282c34;\n  min-height: 100vh;\n  display: flex;\n  flex-direction: column;\n  align-items: center;\n  justify-content: center;\n  font-size: calc(10px + 2vmin);\n  color: white;\n}\n\n.App-link {\n  color: #61dafb;\n}\n\n@keyframes App-logo-spin {\n  from {\n    transform: rotate(0deg);\n  }\n  to {\n    transform: rotate(360deg);\n  }\n}\n"
  },
  {
    "path": "momoka-node/playground-browser/src/App.test.tsx",
    "content": "import React from 'react';\nimport { render, screen } from '@testing-library/react';\nimport App from './App';\n\ntest('renders learn react link', () => {\n  render(<App />);\n  const linkElement = screen.getByText(/learn react/i);\n  expect(linkElement).toBeInTheDocument();\n});\n"
  },
  {
    "path": "momoka-node/playground-browser/src/App.tsx",
    "content": "import {\n  checkDAProof,\n  Deployment,\n  Environment,\n  EthereumNode,\n} from '@lens-protocol/data-availability-verifier/client';\nimport './App.css';\n\nconst ethereumNode: EthereumNode = {\n  environment: Environment.AMOY,\n  nodeUrl: 'INSERT_NODE_URL_HERE',\n  deployment: Deployment.STAGING,\n};\n\nconst check = async () => {\n  const result = await checkDAProof('VlPh9JdZ2SNcnWaqgHFRfycT8xpuoX2MR5LnI95f87w', ethereumNode);\n  if (result.isSuccess()) {\n    console.log('proof valid', result.successResult);\n    return;\n  }\n\n  // it failed!\n  console.error('proof invalid do something', result.failure);\n\n  console.log(ethereumNode);\n};\n\ncheck();\n\nfunction App() {\n  return (\n    <div className=\"App\">\n      <header className=\"App-header\">\n        <p>\n          Edit <code>src/App.tsx</code> and save to reload.\n        </p>\n        <a\n          className=\"App-link\"\n          href=\"https://reactjs.org\"\n          target=\"_blank\"\n          rel=\"noopener noreferrer\"\n        >\n          Learn React\n        </a>\n      </header>\n    </div>\n  );\n}\n\nexport default App;\n"
  },
  {
    "path": "momoka-node/playground-browser/src/index.css",
    "content": "body {\n  margin: 0;\n  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu',\n    'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif;\n  -webkit-font-smoothing: antialiased;\n  -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n  font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', monospace;\n}\n"
  },
  {
    "path": "momoka-node/playground-browser/src/index.tsx",
    "content": "import React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport './index.css';\nimport App from './App';\nimport reportWebVitals from './reportWebVitals';\n\nconst root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);\nroot.render(\n  <React.StrictMode>\n    <App />\n  </React.StrictMode>\n);\n\n// If you want to start measuring performance in your app, pass a function\n// to log results (for example: reportWebVitals(console.log))\n// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals\nreportWebVitals();\n"
  },
  {
    "path": "momoka-node/playground-browser/src/react-app-env.d.ts",
    "content": "/// <reference types=\"react-scripts\" />\n"
  },
  {
    "path": "momoka-node/playground-browser/src/reportWebVitals.ts",
    "content": "import { ReportHandler } from 'web-vitals';\n\nconst reportWebVitals = (onPerfEntry?: ReportHandler) => {\n  if (onPerfEntry && onPerfEntry instanceof Function) {\n    import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => {\n      getCLS(onPerfEntry);\n      getFID(onPerfEntry);\n      getFCP(onPerfEntry);\n      getLCP(onPerfEntry);\n      getTTFB(onPerfEntry);\n    });\n  }\n};\n\nexport default reportWebVitals;\n"
  },
  {
    "path": "momoka-node/playground-browser/src/setupTests.ts",
    "content": "// jest-dom adds custom jest matchers for asserting on DOM nodes.\n// allows you to do things like:\n// expect(element).toHaveTextContent(/react/i)\n// learn more: https://github.com/testing-library/jest-dom\nimport '@testing-library/jest-dom';\n"
  },
  {
    "path": "momoka-node/playground-browser/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es5\",\n    \"lib\": [\"dom\", \"dom.iterable\", \"esnext\"],\n    \"allowJs\": true,\n    \"skipLibCheck\": true,\n    \"esModuleInterop\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"strict\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"noFallthroughCasesInSwitch\": true,\n    \"module\": \"esnext\",\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"isolatedModules\": true,\n    \"noEmit\": true,\n    \"jsx\": \"react-jsx\"\n  },\n  \"include\": [\"src\"]\n}\n"
  },
  {
    "path": "momoka-node/pnpm-workspace.yaml",
    "content": "packages:\n  - 'src/**'\n  # if required, exclude some directories\n  - '!**/test/**'"
  },
  {
    "path": "momoka-node/render.yaml",
    "content": "services:\r\n  - type: worker\r\n    name: momoka\r\n    env: docker\r\n    dockerfilePath: ./Dockerfile.stable\r\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/comment.e2e.test.ts",
    "content": "// apply mocks!\njest.setTimeout(3000);\njest.mock('../input-output/db');\njest.mock('../input-output/bundlr/get-bundlr-by-id.api');\njest.mock('../submitters');\n\nimport { MomokaValidatorError } from '..';\nimport { deepClone } from '../common/helpers';\nimport { DAPublicationPointerType } from '../data-availability-models/publications/data-availability-structure-publication';\nimport { commentCreatedDelegateArweaveResponse } from './mocks/comment/comment-created-delegate-arweave-response.mock';\nimport { commentCreatedWithoutDelegateArweaveResponse } from './mocks/comment/comment-created-without-delegate-arweave-response.mock';\nimport * as sharedMocks from './mocks/shared.mock';\nimport { mockTxValidationResult } from './mocks/shared.mock';\n\ndescribe('comment', () => {\n  describe('with delegate', () => {\n    let baseMock = commentCreatedDelegateArweaveResponse;\n\n    beforeEach(() => {\n      baseMock = commentCreatedDelegateArweaveResponse;\n      sharedMocks.mockGetDAPublicationByIdAPI.mockImplementation(async () =>\n        deepClone(commentCreatedDelegateArweaveResponse)\n      );\n    });\n\n    describe('should return success when', () => {\n      test('signed by delegate is true', async () => {\n        expect(baseMock.chainProofs.thisPublication.signedByDelegate).toBe(true);\n      });\n\n      test('txExists in the db already', async () => {\n        sharedMocks.mockGetTxDb.mockImplementationOnce(async () => null);\n        const result = await sharedMocks.callCheckDAProof();\n        expect(result.isSuccess()).toBe(true);\n      });\n\n      test('tx is valid and passes all the simulation checks', async () => {\n        const result = await sharedMocks.callCheckDAProof();\n        expect(result.isSuccess()).toBe(true);\n      });\n    });\n\n    describe('should return failure when', () => {\n      test('NO_SIGNATURE_SUBMITTER', async () => {\n        sharedMocks.mockImpl__NO_SIGNATURE_SUBMITTER(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NO_SIGNATURE_SUBMITTER);\n      });\n\n      xtest('INVALID_SIGNATURE_SUBMITTER', async () => {\n        sharedMocks.mockIsValidSubmitter.mockImplementationOnce(() => false);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_SIGNATURE_SUBMITTER);\n      });\n\n      test('TIMESTAMP_PROOF_INVALID_SIGNATURE', async () => {\n        sharedMocks.mockImpl__TIMESTAMP_PROOF_INVALID_SIGNATURE(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SIGNATURE\n        );\n      });\n\n      test('TIMESTAMP_PROOF_NOT_SUBMITTER', async () => {\n        sharedMocks.mockImpl__TIMESTAMP_PROOF_NOT_SUBMITTER();\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.TIMESTAMP_PROOF_NOT_SUBMITTER\n        );\n      });\n\n      test('INVALID_EVENT_TIMESTAMP', async () => {\n        sharedMocks.mockImpl__INVALID_EVENT_TIMESTAMP(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_EVENT_TIMESTAMP);\n      });\n\n      xtest('NOT_CLOSEST_BLOCK', async () => {\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NOT_CLOSEST_BLOCK);\n      });\n\n      test('PUBLICATION_NO_POINTER', async () => {\n        sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, null);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NO_POINTER);\n      });\n\n      test('PUBLICATION_NONE_DA', async () => {\n        sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, {\n          type: DAPublicationPointerType.ON_EVM_CHAIN,\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONE_DA);\n      });\n\n      test('PUBLICATION_NONCE_INVALID', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            chainProofs: {\n              ...baseMock.chainProofs,\n              thisPublication: {\n                ...baseMock.chainProofs.thisPublication,\n                typedData: {\n                  ...baseMock.chainProofs.thisPublication.typedData,\n                  value: {\n                    ...baseMock.chainProofs.thisPublication.typedData.value,\n                    nonce: 13234452346523,\n                  },\n                },\n              },\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONCE_INVALID);\n      });\n\n      xtest('PUBLICATION_SIGNER_NOT_ALLOWED', async () => {});\n\n      test('INVALID_FORMATTED_TYPED_DATA', async () => {\n        sharedMocks.mockImpl__INVALID_FORMATTED_TYPED_DATA(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA\n        );\n      });\n\n      test('EVENT_MISMATCH - pub id does not match simulated result', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              pubId: '0x000000000000002',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - profile id does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              profileId: '0x02',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - contentURI does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              contentURI: '__mocked_content_uri__',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - profileIdPointed does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              profileIdPointed: '0x01',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - pubIdPointed does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              pubIdPointed: '0x01',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - collectModule does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              collectModule: '0x0000000000000000000000000000000000000',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - collectModuleReturnData is not empty bytes', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              collectModuleReturnData: 'not_empty_bytes',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - referenceModule does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              referenceModule: '0x0000000000000000000000000000000000001',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - referenceModuleReturnData is not empty bytes', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              referenceModuleReturnData: 'not_empty_bytes',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      xtest('SIMULATION_NODE_COULD_NOT_RUN', async () => {});\n\n      xtest('UNKNOWN', () => {});\n    });\n  });\n\n  describe('without delegate', () => {\n    let baseMock = commentCreatedWithoutDelegateArweaveResponse;\n\n    beforeEach(() => {\n      baseMock = commentCreatedWithoutDelegateArweaveResponse;\n      sharedMocks.mockGetDAPublicationByIdAPI.mockImplementation(async () =>\n        deepClone(commentCreatedWithoutDelegateArweaveResponse)\n      );\n    });\n\n    describe('should return success when', () => {\n      test('signed by delegate is false', async () => {\n        expect(baseMock.chainProofs.thisPublication.signedByDelegate).toBe(false);\n      });\n\n      test('txExists in the db already', async () => {\n        sharedMocks.mockGetTxDb.mockImplementationOnce(async () => mockTxValidationResult);\n        const result = await sharedMocks.callCheckDAProof();\n        expect(result.isSuccess()).toBe(true);\n      });\n\n      test('tx is valid and passes all the simulation checks', async () => {\n        const result = await sharedMocks.callCheckDAProof();\n        expect(result.isSuccess()).toBe(true);\n      });\n    });\n\n    describe('should return failure when', () => {\n      test('NO_SIGNATURE_SUBMITTER', async () => {\n        sharedMocks.mockImpl__NO_SIGNATURE_SUBMITTER(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NO_SIGNATURE_SUBMITTER);\n      });\n\n      xtest('INVALID_SIGNATURE_SUBMITTER', async () => {\n        sharedMocks.mockIsValidSubmitter.mockImplementationOnce(() => false);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_SIGNATURE_SUBMITTER);\n      });\n\n      test('TIMESTAMP_PROOF_INVALID_SIGNATURE', async () => {\n        sharedMocks.mockImpl__TIMESTAMP_PROOF_INVALID_SIGNATURE(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SIGNATURE\n        );\n      });\n\n      test('TIMESTAMP_PROOF_NOT_SUBMITTER', async () => {\n        sharedMocks.mockImpl__TIMESTAMP_PROOF_NOT_SUBMITTER();\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.TIMESTAMP_PROOF_NOT_SUBMITTER\n        );\n      });\n\n      test('INVALID_EVENT_TIMESTAMP', async () => {\n        sharedMocks.mockImpl__INVALID_EVENT_TIMESTAMP(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_EVENT_TIMESTAMP);\n      });\n\n      xtest('NOT_CLOSEST_BLOCK', async () => {\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NOT_CLOSEST_BLOCK);\n      });\n\n      test('PUBLICATION_NO_POINTER', async () => {\n        sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, null);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NO_POINTER);\n      });\n\n      test('PUBLICATION_NONE_DA', async () => {\n        sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, {\n          type: DAPublicationPointerType.ON_EVM_CHAIN,\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONE_DA);\n      });\n\n      test('PUBLICATION_NONCE_INVALID', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            chainProofs: {\n              ...baseMock.chainProofs,\n              thisPublication: {\n                ...baseMock.chainProofs.thisPublication,\n                typedData: {\n                  ...baseMock.chainProofs.thisPublication.typedData,\n                  value: {\n                    ...baseMock.chainProofs.thisPublication.typedData.value,\n                    nonce: 13234452346523,\n                  },\n                },\n              },\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONCE_INVALID);\n      });\n\n      xtest('PUBLICATION_SIGNER_NOT_ALLOWED', async () => {});\n\n      test('INVALID_FORMATTED_TYPED_DATA', async () => {\n        sharedMocks.mockImpl__INVALID_FORMATTED_TYPED_DATA(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA\n        );\n      });\n\n      test('EVENT_MISMATCH - pub id does not match simulated result', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              pubId: '0x000000000000002',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - profile id does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              profileId: '0x02',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - contentURI does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              contentURI: '__mocked_content_uri__',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - profileIdPointed does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              profileIdPointed: '0x01',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - pubIdPointed does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              pubIdPointed: '0x01',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - collectModule does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              collectModule: '0x0000000000000000000000000000000000000',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - collectModuleReturnData is not empty bytes', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              collectModuleReturnData: 'not_empty_bytes',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - referenceModule does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              referenceModule: '0x0000000000000000000000000000000000001',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - referenceModuleReturnData is not empty bytes', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              referenceModuleReturnData: 'not_empty_bytes',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      xtest('SIMULATION_NODE_COULD_NOT_RUN', async () => {});\n\n      xtest('UNKNOWN', () => {});\n    });\n  });\n});\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/config/jest.setup.js",
    "content": "const crypto = require('crypto');\n\nObject.defineProperty(globalThis, 'crypto', {\n  value: {\n    subtle: crypto.webcrypto.subtle,\n  },\n});\n\n// eslint-disable-next-line no-undef\njest.setTimeout(15000);\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/db.test.ts",
    "content": "import { MomokaValidatorError, TxValidatedResult } from '..';\nimport { getBlockDb, getTxDb, saveBlockDb, saveTxDb, startDb } from '../input-output/db';\n\nconst random = () => Math.random().toString(36).substring(7);\n\nconst txValidatedResult: TxValidatedResult = {\n  success: false,\n  proofTxId: random(),\n  failureReason: MomokaValidatorError.BLOCK_CANT_BE_READ_FROM_NODE,\n  dataAvailabilityResult: undefined,\n};\n\ndescribe('db', () => {\n  beforeAll(async () => {\n    await startDb();\n  });\n\n  describe('getTxDb', () => {\n    test('should return back false if tx does not exist', async () => {\n      const txId = random();\n      const result = await getTxDb(txId);\n      expect(result).toBeNull();\n    });\n\n    test('should return back true if tx exists', async () => {\n      const txId = random();\n      await saveTxDb(txId, txValidatedResult);\n      const result = await getTxDb(txId);\n      expect(result).toEqual(txValidatedResult);\n    });\n  });\n\n  describe('saveTxDb', () => {\n    test('should save to db', async () => {\n      const txId = random();\n      await saveTxDb(txId, txValidatedResult);\n      const result = await getTxDb(txId);\n      expect(result).toEqual(txValidatedResult);\n    });\n  });\n\n  describe('getBlockDb + saveBlockDb', () => {\n    test('should return null if nothing found', async () => {\n      const ran = random();\n      const result = await getBlockDb(ran as any);\n      expect(result).toEqual(null);\n    });\n\n    test('should return value if found', async () => {\n      const ran = random();\n      const block = { number: ran as any } as any;\n\n      await saveBlockDb(block);\n\n      const result = await getBlockDb(ran as any);\n      expect(result).toEqual(block);\n    });\n  });\n});\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/mirror.e2e.test.ts",
    "content": "// apply mocks!\njest.setTimeout(30000);\njest.mock('../input-output/db');\njest.mock('../input-output/bundlr/get-bundlr-by-id.api');\njest.mock('../submitters');\n\nimport { MomokaValidatorError } from '..';\nimport { deepClone } from '../common/helpers';\nimport { DAPublicationPointerType } from '../data-availability-models/publications/data-availability-structure-publication';\nimport { mirrorCreatedDelegateCommentArweaveResponse } from './mocks/mirror/mirror-created-delegate-comment-arweave-response.mock';\nimport { mirrorCreatedDelegatePostArweaveResponse } from './mocks/mirror/mirror-created-delegate-post-arweave-response.mock';\nimport { mirrorCreatedWithoutDelegateCommentArweaveResponse } from './mocks/mirror/mirror-created-without-delegate-comment-arweave-response.mock';\nimport { mirrorCreatedWithoutDelegatePostArweaveResponse } from './mocks/mirror/mirror-created-without-delegate-post-arweave-response.mock';\nimport * as sharedMocks from './mocks/shared.mock';\nimport { mockTxValidationResult } from './mocks/shared.mock';\n\ndescribe('mirror', () => {\n  describe('post', () => {\n    describe('with delegate', () => {\n      let baseMock = mirrorCreatedDelegatePostArweaveResponse;\n\n      beforeEach(() => {\n        baseMock = mirrorCreatedDelegatePostArweaveResponse;\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementation(async () =>\n          deepClone(mirrorCreatedDelegatePostArweaveResponse)\n        );\n      });\n\n      describe('should return success when', () => {\n        test('signed by delegate is true', () => {\n          expect(baseMock.chainProofs.thisPublication.signedByDelegate).toBe(true);\n        });\n\n        test('txExists in the db already', async () => {\n          sharedMocks.mockGetTxDb.mockImplementationOnce(async () => mockTxValidationResult);\n          const result = await sharedMocks.callCheckDAProof();\n          expect(result.isSuccess()).toBe(true);\n        });\n\n        test('tx is valid and passes all the simulation checks', async () => {\n          sharedMocks.mockIsValidSubmitter.mockImplementationOnce(() => true);\n          const result = await sharedMocks.callCheckDAProof();\n          expect(result.isSuccess()).toBe(true);\n        });\n      });\n\n      describe('should return failure when', () => {\n        test('NO_SIGNATURE_SUBMITTER', async () => {\n          sharedMocks.mockImpl__NO_SIGNATURE_SUBMITTER(baseMock);\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NO_SIGNATURE_SUBMITTER);\n        });\n\n        xtest('INVALID_SIGNATURE_SUBMITTER', async () => {\n          sharedMocks.mockIsValidSubmitter.mockImplementationOnce(() => false);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.INVALID_SIGNATURE_SUBMITTER\n          );\n        });\n\n        test('TIMESTAMP_PROOF_INVALID_SIGNATURE', async () => {\n          sharedMocks.mockImpl__TIMESTAMP_PROOF_INVALID_SIGNATURE(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SIGNATURE\n          );\n        });\n\n        test('TIMESTAMP_PROOF_NOT_SUBMITTER', async () => {\n          sharedMocks.mockImpl__TIMESTAMP_PROOF_NOT_SUBMITTER();\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.TIMESTAMP_PROOF_NOT_SUBMITTER\n          );\n        });\n\n        test('INVALID_EVENT_TIMESTAMP', async () => {\n          sharedMocks.mockImpl__INVALID_EVENT_TIMESTAMP(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_EVENT_TIMESTAMP);\n        });\n\n        xtest('NOT_CLOSEST_BLOCK', async () => {\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NOT_CLOSEST_BLOCK);\n        });\n\n        test('PUBLICATION_NO_POINTER', async () => {\n          sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, null);\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NO_POINTER);\n        });\n\n        test('PUBLICATION_NONE_DA', async () => {\n          sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, {\n            type: DAPublicationPointerType.ON_EVM_CHAIN,\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONE_DA);\n        });\n\n        test('PUBLICATION_NONCE_INVALID', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              chainProofs: {\n                ...baseMock.chainProofs,\n                thisPublication: {\n                  ...baseMock.chainProofs.thisPublication,\n                  typedData: {\n                    ...baseMock.chainProofs.thisPublication.typedData,\n                    value: {\n                      ...baseMock.chainProofs.thisPublication.typedData.value,\n                      nonce: 13234452346523,\n                    },\n                  },\n                },\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONCE_INVALID);\n        });\n\n        xtest('PUBLICATION_SIGNER_NOT_ALLOWED', async () => {});\n\n        test('INVALID_FORMATTED_TYPED_DATA', async () => {\n          sharedMocks.mockImpl__INVALID_FORMATTED_TYPED_DATA(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA\n          );\n        });\n\n        test('EVENT_MISMATCH - pub id does not match simulated result', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return await {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                pubId: '0x000000000000002',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - profile id does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                profileId: '0x02',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - profileIdPointed does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                profileIdPointed: '0x01',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - pubIdPointed does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                pubIdPointed: '0x01',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - referenceModule does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                referenceModule: '0x0000000000000000000000000000000000001',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - referenceModuleReturnData is not empty bytes', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                referenceModuleReturnData: 'not_empty_bytes',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        xtest('SIMULATION_NODE_COULD_NOT_RUN', async () => {});\n\n        xtest('INVALID_POINTER_SET_NOT_NEEDED', () => {});\n\n        xtest('UNKNOWN', () => {});\n      });\n    });\n\n    describe('without delegate', () => {\n      let baseMock = mirrorCreatedWithoutDelegatePostArweaveResponse;\n\n      beforeEach(() => {\n        baseMock = mirrorCreatedWithoutDelegatePostArweaveResponse;\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementation(async () =>\n          deepClone(mirrorCreatedWithoutDelegatePostArweaveResponse)\n        );\n      });\n\n      describe('should return success when', () => {\n        test('signed by delegate is false', async () => {\n          expect(baseMock.chainProofs.thisPublication.signedByDelegate).toBe(false);\n        });\n\n        test('txExists in the db already', async () => {\n          sharedMocks.mockGetTxDb.mockImplementationOnce(async () => mockTxValidationResult);\n          const result = await sharedMocks.callCheckDAProof();\n          expect(result.isSuccess()).toBe(true);\n        });\n\n        test('tx is valid and passes all the simulation checks', async () => {\n          const result = await sharedMocks.callCheckDAProof();\n          expect(result.isSuccess()).toBe(true);\n        });\n      });\n\n      describe('should return failure when', () => {\n        test('NO_SIGNATURE_SUBMITTER', async () => {\n          sharedMocks.mockImpl__NO_SIGNATURE_SUBMITTER(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NO_SIGNATURE_SUBMITTER);\n        });\n\n        xtest('INVALID_SIGNATURE_SUBMITTER', async () => {\n          sharedMocks.mockIsValidSubmitter.mockImplementationOnce(() => false);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.INVALID_SIGNATURE_SUBMITTER\n          );\n        });\n\n        test('TIMESTAMP_PROOF_INVALID_SIGNATURE', async () => {\n          sharedMocks.mockImpl__TIMESTAMP_PROOF_INVALID_SIGNATURE(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SIGNATURE\n          );\n        });\n\n        test('TIMESTAMP_PROOF_NOT_SUBMITTER', async () => {\n          sharedMocks.mockImpl__TIMESTAMP_PROOF_NOT_SUBMITTER();\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.TIMESTAMP_PROOF_NOT_SUBMITTER\n          );\n        });\n\n        test('INVALID_EVENT_TIMESTAMP', async () => {\n          sharedMocks.mockImpl__INVALID_EVENT_TIMESTAMP(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_EVENT_TIMESTAMP);\n        });\n\n        xtest('NOT_CLOSEST_BLOCK', async () => {\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NOT_CLOSEST_BLOCK);\n        });\n\n        test('PUBLICATION_NO_POINTER', async () => {\n          sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, null);\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NO_POINTER);\n        });\n\n        test('PUBLICATION_NONE_DA', async () => {\n          sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, {\n            type: DAPublicationPointerType.ON_EVM_CHAIN,\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONE_DA);\n        });\n\n        test('PUBLICATION_NONCE_INVALID', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              chainProofs: {\n                ...baseMock.chainProofs,\n                thisPublication: {\n                  ...baseMock.chainProofs.thisPublication,\n                  typedData: {\n                    ...baseMock.chainProofs.thisPublication.typedData,\n                    value: {\n                      ...baseMock.chainProofs.thisPublication.typedData.value,\n                      nonce: 13234452346523,\n                    },\n                  },\n                },\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONCE_INVALID);\n        });\n\n        xtest('PUBLICATION_SIGNER_NOT_ALLOWED', async () => {});\n\n        test('INVALID_FORMATTED_TYPED_DATA', async () => {\n          sharedMocks.mockImpl__INVALID_FORMATTED_TYPED_DATA(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA\n          );\n        });\n\n        test('EVENT_MISMATCH - pub id does not match simulated result', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                pubId: '0x000000000000002',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - profile id does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                profileId: '0x02',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - profileIdPointed does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                profileIdPointed: '0x01',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - pubIdPointed does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                pubIdPointed: '0x01',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - referenceModule does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                referenceModule: '0x0000000000000000000000000000000000001',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - referenceModuleReturnData is not empty bytes', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                referenceModuleReturnData: 'not_empty_bytes',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        xtest('SIMULATION_NODE_COULD_NOT_RUN', async () => {});\n\n        xtest('INVALID_POINTER_SET_NOT_NEEDED', () => {});\n\n        xtest('UNKNOWN', () => {});\n      });\n    });\n  });\n\n  describe('comment', () => {\n    describe('with delegate', () => {\n      let baseMock = mirrorCreatedDelegateCommentArweaveResponse;\n\n      beforeEach(() => {\n        baseMock = mirrorCreatedDelegateCommentArweaveResponse;\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementation(async () =>\n          deepClone(mirrorCreatedDelegateCommentArweaveResponse)\n        );\n      });\n\n      describe('should return success when', () => {\n        test('signed by delegate is true', async () => {\n          expect(baseMock.chainProofs.thisPublication.signedByDelegate).toBe(true);\n        });\n\n        test('txExists in the db already', async () => {\n          sharedMocks.mockGetTxDb.mockImplementationOnce(async () => mockTxValidationResult);\n          const result = await sharedMocks.callCheckDAProof();\n          expect(result.isSuccess()).toBe(true);\n        });\n\n        test('tx is valid and passes all the simulation checks', async () => {\n          const result = await sharedMocks.callCheckDAProof();\n          expect(result.isSuccess()).toBe(true);\n        });\n      });\n\n      describe('should return failure when', () => {\n        test('NO_SIGNATURE_SUBMITTER', async () => {\n          sharedMocks.mockImpl__NO_SIGNATURE_SUBMITTER(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NO_SIGNATURE_SUBMITTER);\n        });\n\n        xtest('INVALID_SIGNATURE_SUBMITTER', async () => {\n          sharedMocks.mockIsValidSubmitter.mockImplementationOnce(() => false);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.INVALID_SIGNATURE_SUBMITTER\n          );\n        });\n\n        test('TIMESTAMP_PROOF_INVALID_SIGNATURE', async () => {\n          sharedMocks.mockImpl__TIMESTAMP_PROOF_INVALID_SIGNATURE(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SIGNATURE\n          );\n        });\n\n        test('TIMESTAMP_PROOF_NOT_SUBMITTER', async () => {\n          sharedMocks.mockImpl__TIMESTAMP_PROOF_NOT_SUBMITTER();\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.TIMESTAMP_PROOF_NOT_SUBMITTER\n          );\n        });\n\n        test('INVALID_EVENT_TIMESTAMP', async () => {\n          sharedMocks.mockImpl__INVALID_EVENT_TIMESTAMP(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_EVENT_TIMESTAMP);\n        });\n\n        xtest('NOT_CLOSEST_BLOCK', async () => {\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NOT_CLOSEST_BLOCK);\n        });\n\n        test('PUBLICATION_NO_POINTER', async () => {\n          sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, null);\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NO_POINTER);\n        });\n\n        test('PUBLICATION_NONE_DA', async () => {\n          sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, {\n            type: DAPublicationPointerType.ON_EVM_CHAIN,\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONE_DA);\n        });\n\n        test('PUBLICATION_NONCE_INVALID', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              chainProofs: {\n                ...baseMock.chainProofs,\n                thisPublication: {\n                  ...baseMock.chainProofs.thisPublication,\n                  typedData: {\n                    ...baseMock.chainProofs.thisPublication.typedData,\n                    value: {\n                      ...baseMock.chainProofs.thisPublication.typedData.value,\n                      nonce: 13234452346523,\n                    },\n                  },\n                },\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONCE_INVALID);\n        });\n\n        xtest('PUBLICATION_SIGNER_NOT_ALLOWED', async () => {});\n\n        test('INVALID_FORMATTED_TYPED_DATA', async () => {\n          sharedMocks.mockImpl__INVALID_FORMATTED_TYPED_DATA(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA\n          );\n        });\n\n        test('EVENT_MISMATCH - pub id does not match simulated result', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                pubId: '0x000000000000002',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - profile id does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                profileId: '0x02',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - profileIdPointed does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                profileIdPointed: '0x01',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - pubIdPointed does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                pubIdPointed: '0x01',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - referenceModule does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                referenceModule: '0x0000000000000000000000000000000000001',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - referenceModuleReturnData is not empty bytes', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                referenceModuleReturnData: 'not_empty_bytes',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        xtest('SIMULATION_NODE_COULD_NOT_RUN', async () => {});\n\n        xtest('INVALID_POINTER_SET_NOT_NEEDED', () => {});\n\n        xtest('UNKNOWN', () => {});\n      });\n    });\n\n    describe('without delegate', () => {\n      let baseMock = mirrorCreatedWithoutDelegateCommentArweaveResponse;\n\n      beforeEach(() => {\n        baseMock = mirrorCreatedWithoutDelegateCommentArweaveResponse;\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementation(async () =>\n          deepClone(mirrorCreatedWithoutDelegateCommentArweaveResponse)\n        );\n      });\n\n      describe('should return success when', () => {\n        test('signed by delegate is false', async () => {\n          expect(baseMock.chainProofs.thisPublication.signedByDelegate).toBe(false);\n        });\n\n        test('txExists in the db already', async () => {\n          sharedMocks.mockGetTxDb.mockImplementationOnce(async () => mockTxValidationResult);\n          const result = await sharedMocks.callCheckDAProof();\n          expect(result.isSuccess()).toBe(true);\n        });\n\n        test('tx is valid and passes all the simulation checks', async () => {\n          const result = await sharedMocks.callCheckDAProof();\n          expect(result.isSuccess()).toBe(true);\n        });\n      });\n\n      describe('should return failure when', () => {\n        test('NO_SIGNATURE_SUBMITTER', async () => {\n          sharedMocks.mockImpl__NO_SIGNATURE_SUBMITTER(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NO_SIGNATURE_SUBMITTER);\n        });\n\n        xtest('INVALID_SIGNATURE_SUBMITTER', async () => {\n          sharedMocks.mockIsValidSubmitter.mockImplementationOnce(() => false);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.INVALID_SIGNATURE_SUBMITTER\n          );\n        });\n\n        test('TIMESTAMP_PROOF_INVALID_SIGNATURE', async () => {\n          sharedMocks.mockImpl__TIMESTAMP_PROOF_INVALID_SIGNATURE(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SIGNATURE\n          );\n        });\n\n        test('TIMESTAMP_PROOF_NOT_SUBMITTER', async () => {\n          sharedMocks.mockImpl__TIMESTAMP_PROOF_NOT_SUBMITTER();\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.TIMESTAMP_PROOF_NOT_SUBMITTER\n          );\n        });\n\n        test('INVALID_EVENT_TIMESTAMP', async () => {\n          sharedMocks.mockImpl__INVALID_EVENT_TIMESTAMP(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_EVENT_TIMESTAMP);\n        });\n\n        xtest('NOT_CLOSEST_BLOCK', async () => {\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NOT_CLOSEST_BLOCK);\n        });\n\n        test('PUBLICATION_NO_POINTER', async () => {\n          sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, null);\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NO_POINTER);\n        });\n\n        test('PUBLICATION_NONE_DA', async () => {\n          sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, {\n            type: DAPublicationPointerType.ON_EVM_CHAIN,\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONE_DA);\n        });\n\n        test('PUBLICATION_NONCE_INVALID', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              chainProofs: {\n                ...baseMock.chainProofs,\n                thisPublication: {\n                  ...baseMock.chainProofs.thisPublication,\n                  typedData: {\n                    ...baseMock.chainProofs.thisPublication.typedData,\n                    value: {\n                      ...baseMock.chainProofs.thisPublication.typedData.value,\n                      nonce: 13234452346523,\n                    },\n                  },\n                },\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.PUBLICATION_NONCE_INVALID);\n        });\n\n        xtest('PUBLICATION_SIGNER_NOT_ALLOWED', async () => {});\n\n        test('INVALID_FORMATTED_TYPED_DATA', async () => {\n          sharedMocks.mockImpl__INVALID_FORMATTED_TYPED_DATA(baseMock);\n\n          await sharedMocks.checkAndValidateDAProof(\n            MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA\n          );\n        });\n\n        test('EVENT_MISMATCH - pub id does not match simulated result', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                pubId: '0x000000000000002',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - profile id does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                profileId: '0x02',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - profileIdPointed does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                profileIdPointed: '0x01',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - pubIdPointed does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                pubIdPointed: '0x01',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - referenceModule does not match typed data', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                referenceModule: '0x0000000000000000000000000000000000001',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        test('EVENT_MISMATCH - referenceModuleReturnData is not empty bytes', async () => {\n          sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n            return {\n              ...baseMock,\n              event: {\n                ...baseMock.event,\n                referenceModuleReturnData: 'not_empty_bytes',\n              },\n            };\n          });\n\n          await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n        });\n\n        xtest('SIMULATION_NODE_COULD_NOT_RUN', async () => {});\n\n        xtest('INVALID_POINTER_SET_NOT_NEEDED', () => {});\n\n        xtest('UNKNOWN', () => {});\n      });\n    });\n  });\n});\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/mocks/comment/comment-created-delegate-arweave-response.mock.ts",
    "content": "import { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { MomokaProvider } from '../../../data-availability-models/data-availability-provider';\nimport {\n  DAPublicationPointerType,\n  DAStructurePublication,\n} from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DACommentCreatedEventEmittedResponse } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { CreateCommentV1EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\n\nexport const commentCreatedDelegateArweaveResponse: DAStructurePublication<\n  DACommentCreatedEventEmittedResponse,\n  CreateCommentV1EIP712TypedData\n> = {\n  signature:\n    '0xd422257695bbc5cd9e75e128c864b1a498fa281673d91d972edafdcc8459fdef7f755343ebf5a39ab32189425df653d2c31b908d9f6142c41ae6b59b125804201b',\n  dataAvailabilityId: '1f337269-6e83-4e91-94e0-7da2038d1a8b',\n  type: MomokaActionTypes.COMMENT_CREATED,\n  timestampProofs: {\n    type: MomokaProvider.BUNDLR,\n    hashPrefix: '1',\n    response: {\n      id: 'AkE_aGaF0V-gacWAZ8H5G9y79sidDOTKrpFGoMsrQcs',\n      timestamp: 1674740686651,\n      version: '1.0.0',\n      public:\n        'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n      signature:\n        'GrviEYIyWdX1RLjEK32cV-F9ZyCXYtKT29YFxz5LGqOqKvqjRA0KWoEqgotrMI7fVg7geuKf5gT9QFJ9_UjqgE0aCblGrrAXa_NtVF37Smec4yBwhsALuDnnXZugyltkYAWms-gHsZ5VPiFmA0Yzo3I5OcLGMGq5Isjcbo56AzXEFUVQaNKhZ8h9DLsPzkpRbU1hMAp-niPBBYF3pclT-Lfg1XaZAK0I81LMX5IzObI4W4ECwBTjy0_T5jFD_THlfqJqloBOaGHgTxcnFcQGSJb30zopvrhkEfnjtM8OErHY2iuqAINdXHPikpkeNAeVsIHtFss9BnSaHnPniT2Cbf4AMnaCndFNTEaY1N8CWn2RqmMbfLaoO1vdwg_XbFVrq1JmPBGhvLFz6K5t9UoclgE8HiWpgEgU_GiauL4GXPQiWz85J77DKXPodC6xQFQenU1vM0y2QZ5VZ6wt9K_R2NJjyTBjNR1rnbcC6hVUWJ_Jm4QxeOrdM8CJDmdPws3RniJBtX5UggE1zG1riQdgAevTLSuj8b9Wh0zr_zz1OUmVjrhYAfeKA4vBJ3hxjuMFe_epAx9rKh_zLlHoTJcaau40_x_hjupQS4imGBy9vSDfS-oUGHhI3UX041FFZ8mvSOvqN0oPe4d9iL2Om2bHpyjBr5qDm_B5p21520pf85Q',\n      deadlineHeight: 1106561,\n      block: 1106561,\n      validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n      signature:\n        '0xe1947e75a0ba8d56a77a19ec8b67b5e6e277c5cc9f968e5f230b158ed0896eaf0b0e5fd15bd7895a685e7bff8bec17c3123ff855b11e8ad9522d3667d9e584091c',\n      signedByDelegate: true,\n      signatureDeadline: 1674740685,\n      typedData: {\n        types: {\n          CommentWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'contentURI',\n              type: 'string',\n            },\n            {\n              name: 'profileIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'pubIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'referenceModuleData',\n              type: 'bytes',\n            },\n            {\n              name: 'collectModule',\n              type: 'address',\n            },\n            {\n              name: 'collectModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        value: {\n          profileId: '0x18',\n          profileIdPointed: '0x18',\n          pubIdPointed: '0x3a',\n          contentURI: 'ar://xd0iTVH-FZyZKjGh7KY8E3MyNT1qbdbZYVrB_OQfvIw',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n          collectModuleInitData: '0x',\n          referenceModuleInitData: '0x',\n          referenceModuleData: '0x',\n          nonce: 0,\n          deadline: 1674740685,\n        },\n      },\n      blockHash: '0xa4b833e32ff44b7d55e1dfc662959790ef684c153f060a4ad1f52281b2ac8f72',\n      blockNumber: 31431635,\n      blockTimestamp: 1674740685,\n    },\n    pointer: {\n      location: 'ar://TEoFkgD0m-LLQkfViuCTKfCLK_xpSxzPUNoMjBLnvlI',\n      type: DAPublicationPointerType.ON_DA,\n    },\n  },\n  publicationId: '0x18-0x3a-DA-1f337269',\n  event: {\n    profileId: '0x18',\n    pubId: '0x3a',\n    contentURI: 'ar://xd0iTVH-FZyZKjGh7KY8E3MyNT1qbdbZYVrB_OQfvIw',\n    profileIdPointed: '0x18',\n    pubIdPointed: '0x3a',\n    referenceModuleData: '0x',\n    collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n    collectModuleReturnData: '0x',\n    referenceModule: '0x0000000000000000000000000000000000000000',\n    referenceModuleReturnData: '0x',\n    timestamp: 1674740685,\n  },\n};\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/mocks/comment/comment-created-without-delegate-arweave-response.mock.ts",
    "content": "import { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { MomokaProvider } from '../../../data-availability-models/data-availability-provider';\nimport {\n  DAPublicationPointerType,\n  DAStructurePublication,\n} from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DACommentCreatedEventEmittedResponse } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { CreateCommentV1EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\n\nexport const commentCreatedWithoutDelegateArweaveResponse: DAStructurePublication<\n  DACommentCreatedEventEmittedResponse,\n  CreateCommentV1EIP712TypedData\n> = {\n  signature:\n    '0xcd9824d89bd3b237ed1230cf914630d756cae83904d835a1e85d37c11dbfab5e42c1f02042469ab29a3ccbd428c9a64576ad77f5876130b9c2bd49e0a83e9b7c1c',\n  dataAvailabilityId: '9a0b1d2b-e36e-48fc-87b4-b5f3f509b494',\n  type: MomokaActionTypes.COMMENT_CREATED,\n  timestampProofs: {\n    type: MomokaProvider.BUNDLR,\n    hashPrefix: '1',\n    response: {\n      id: 'xtVsUj5j1T4T86IQlJk2u-KubGD5oKIXOJQlU3KyGR0',\n      timestamp: 1674747795383,\n      version: '1.0.0',\n      public:\n        'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n      signature:\n        'TZh1F7z14pbuHq7IBlHqnhT4PXEa2dQngiL-iHEXot3-w_ScVLyN9naCeuHvAP4mialS62YPucToy4o1UQlMEtTYS2i6C0rPap32xGi2yDA6AtzURf-xELI33em-mr9QIEuOph34t0yRLn3_Bl0n-AV4jyjVSgHdYjUT0vNZx3TbRkBi_v0PgJHDYkyezP_NrZgTomEe_VZmBgozc0J9zzK6atbIdsPnHYDbY3qzTujJEwogVQa311lNZvVe2ND6MR_0EUyVVW0esin6dyYEIPPCrjlFwMMgaoW4vBbGd1d11cRGopYgNvcX_0EuwAWYGwi8XW_GNGyrk4Df14VnOXAuP4NKd5oia820Be1vqwuAs3ubWX0OQ7CttOgohO9ns7CjYg9DVIwY5-AuJd2wAK6eI09fot-lTNVwtMVBvyxQ4GWaYspMcqkpysOY-5ow0wFp7K4Ad1FI4NO71cbEZQWD8ou08_A5Gd2a6qZF2fb7IJKka0aim26N858faf1nqViZfL-aym-AW60ydNav8inrTxVTMXml61WeG4KwlQXDrdoWkEquLB-1mJ-_519ozgy0QjSbyctp4LjpDpdp-yiJvzfweMFVRIKxarVB9Vvc0NFhyllE8sZud8zLBZ7wo7GG_1wijCJaICo-iD_FK97ZegnhotGLzeDC-KqY2vQ',\n      deadlineHeight: 1106619,\n      block: 1106619,\n      validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n      signature:\n        '0x5156c7e636be61a305373df811d8444b7715448e2bde3fe69d388f301270d83d72796c5ef58283c1a9d32b37033a6b567a32addb78aedef0957fbf56956cd2351b',\n      signedByDelegate: false,\n      signatureDeadline: 1674747793,\n      typedData: {\n        types: {\n          CommentWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'contentURI',\n              type: 'string',\n            },\n            {\n              name: 'profileIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'pubIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'referenceModuleData',\n              type: 'bytes',\n            },\n            {\n              name: 'collectModule',\n              type: 'address',\n            },\n            {\n              name: 'collectModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        value: {\n          profileId: '0x18',\n          profileIdPointed: '0x18',\n          pubIdPointed: '0x3a',\n          contentURI: 'ar://5JNO_BIyW7sD8crn1PPt3SrCZUKF9t-f8Rs13Zh1w1Q',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n          collectModuleInitData: '0x',\n          referenceModuleInitData: '0x',\n          referenceModuleData: '0x',\n          nonce: 243,\n          deadline: 1674747793,\n        },\n      },\n      blockHash: '0x11b2e5b1b7fa87c3a30d10d6f0416f5cb540c30ac7ae4b1be5058d9b5031e172',\n      blockNumber: 31434975,\n      blockTimestamp: 1674747793,\n    },\n    pointer: {\n      location: 'ar://TEoFkgD0m-LLQkfViuCTKfCLK_xpSxzPUNoMjBLnvlI',\n      type: DAPublicationPointerType.ON_DA,\n    },\n  },\n  publicationId: '0x18-0x3a-DA-9a0b1d2b',\n  event: {\n    profileId: '0x18',\n    pubId: '0x3a',\n    contentURI: 'ar://5JNO_BIyW7sD8crn1PPt3SrCZUKF9t-f8Rs13Zh1w1Q',\n    profileIdPointed: '0x18',\n    pubIdPointed: '0x3a',\n    referenceModuleData: '0x',\n    collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n    collectModuleReturnData: '0x',\n    referenceModule: '0x0000000000000000000000000000000000000000',\n    referenceModuleReturnData: '0x',\n    timestamp: 1674747793,\n  },\n};\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/mocks/mirror/mirror-created-delegate-comment-arweave-response.mock.ts",
    "content": "import { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { MomokaProvider } from '../../../data-availability-models/data-availability-provider';\nimport {\n  DAPublicationPointerType,\n  DAStructurePublication,\n} from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAMirrorCreatedEventEmittedResponse } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { CreateMirrorV1EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\n\nexport const mirrorCreatedDelegateCommentArweaveResponse: DAStructurePublication<\n  DAMirrorCreatedEventEmittedResponse,\n  CreateMirrorV1EIP712TypedData\n> = {\n  signature:\n    '0x9480369047ce27715600bdbf391dec6e4b62c36cd1840b5def450f78398ae2007f6b4c520343819bc2fe15a0e5835e4cfe577900522e8a526ae042e6186884961b',\n  dataAvailabilityId: '1cc575ce-3c64-4ab5-bdb9-a13153b0afc1',\n  type: MomokaActionTypes.MIRROR_CREATED,\n  timestampProofs: {\n    type: MomokaProvider.BUNDLR,\n    hashPrefix: '1',\n    response: {\n      id: 's-CnsDdnEn5aaz8pFKdq897bQUtiCmHY263zJrfQ5xA',\n      timestamp: 1674748249813,\n      version: '1.0.0',\n      public:\n        'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n      signature:\n        'k9Kk_0U5Dp6EExgM7EqSwddDK7xbylo26hV-QuskavGn8hajXKRRv26Vl7iOz8GF8Rc1KKhn5LzwBSzH7fLeb7wyKYHm0NjKVOcl6EN__kpD982WAkNlbgST2v0s8R6ZttVMad_MiqETsIqAgA67RwGeOC7cMNkS1rMLXX_CULhWNne8v-bp_Tnvnfhvp6r66sz0STi8gDhcKT26btV-WT7NskIOfJlVz97f0IGcoFr7-DUQU9tT5Y2a8Vwk52w_iUwIioDhNmkWmdyP-9fw-3qESGmFjFXpzpN437wd9N2ekWowFExgfHLSgscTdi_68csJUqbkD0DbGLkFphwYc8KX3A4R1yTDo-uOOWCvZySFUMDVLLw1Xgm0tJCI7aX8-xmO2-BSOZeJ9jx5RVG7uSY2gecdAehHOpkijAcgZzK6f6lz56phKZPOieoXdfkBHgnk2BAbDuAo7ZMz1deS85w6A0TEN_etSY0s5hhWJv8Sm4w8PuRpomG14drFJ5R9QaZFuqialgusenOT9MqSPhBstfjQj1rV7xfqU-uldKbQH5a--_La_uRYjxnGWOuMXq1_6pAt55l0v_zuDJbOWexEn1mL4TBsntEEu-CDN04-nmGns1cwI4MNlrLCWUdKiwZK1Up_CfLCeBzkwVOz0FXGaaPoBffkWDlq-AiW0PY',\n      deadlineHeight: 1106621,\n      block: 1106621,\n      validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n      signature:\n        '0x0fedbd19cf72c37193154ae05fb45ebcfc006bd54e5d5030f015eafe0614cfb07165814023aad71c569a70cc78ee6cd2f33b92f7d27189bae498945f10d2fc501c',\n      signedByDelegate: true,\n      signatureDeadline: 1674748249,\n      typedData: {\n        types: {\n          MirrorWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'profileIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'pubIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'referenceModuleData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        value: {\n          profileId: '0x18',\n          profileIdPointed: '0x18',\n          pubIdPointed: '0x3a',\n          referenceModuleData: '0x',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          referenceModuleInitData: '0x',\n          nonce: 0,\n          deadline: 1674748249,\n        },\n      },\n      blockHash: '0x86a48c0edc9dcc60bbcf83a785fcadb83820fc588c6d8eafed3c50d75c33b6ae',\n      blockNumber: 31435186,\n      blockTimestamp: 1674748249,\n    },\n    pointer: {\n      location: 'ar://b_Sdj7RRevayrg3ybcxyDHdwQAB3DgD-n8_SFXmROtU',\n      type: DAPublicationPointerType.ON_DA,\n    },\n  },\n  publicationId: '0x18-0x3a-DA-1cc575ce',\n  event: {\n    profileId: '0x18',\n    pubId: '0x3a',\n    profileIdPointed: '0x18',\n    pubIdPointed: '0x3a',\n    referenceModuleData: '0x',\n    referenceModule: '0x0000000000000000000000000000000000000000',\n    referenceModuleReturnData: '0x',\n    timestamp: 1674748249,\n  },\n};\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/mocks/mirror/mirror-created-delegate-post-arweave-response.mock.ts",
    "content": "import { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { MomokaProvider } from '../../../data-availability-models/data-availability-provider';\nimport { CreateMirrorV1EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport {\n  DAPublicationPointerType,\n  DAStructurePublication,\n} from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAMirrorCreatedEventEmittedResponse } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\n\nexport const mirrorCreatedDelegatePostArweaveResponse: DAStructurePublication<\n  DAMirrorCreatedEventEmittedResponse,\n  CreateMirrorV1EIP712TypedData\n> = {\n  signature:\n    '0x11a14ad03435338c5548154119cf151f0b827ee4598130ad3220d0fb995c24c658d47bb3f5ac88368fd654b707d74a1d1116f08e86336ddef8351ddb537ace401b',\n  dataAvailabilityId: '6534728f-e7d6-47b6-94d7-8608230c4928',\n  type: MomokaActionTypes.MIRROR_CREATED,\n  timestampProofs: {\n    type: MomokaProvider.BUNDLR,\n    hashPrefix: '1',\n    response: {\n      id: 'PX-Xd26m3pu_lkpeRzlBftrRAExFQOsLLEEL6eVPEoY',\n      timestamp: 1674747937133,\n      version: '1.0.0',\n      public:\n        'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n      signature:\n        'UCzXhdjqGvJv-lej9c1QWP0SPAwlOZ_VeKtYQcFIuUQoOyGYoLql9pSA41KIBCyfp7h54binDtmWRPeTckHoBb6S2Kcje3PJZwmplIL24IPVJZJdCMyWuyHWTPHxV0VTwxatOXKKMF5CNv5QopcO-1DeysQNtVGlRLZMnlMdyKT9ZUbMpxM1TQ7-HQtCT_FLxGRzAybg1Bbm8R6XkD5nioeIbt_4BZq5t1Bh4R1KOzr6iJopyTF44WkHGtunnyNrp3Czt2zOyvt4hVXoK36A3pbSD0dqH17EpcbpOlVr-piHd6pRLwdUVjVsddTwDg94Fzroafkb6OP-v_2yxTiUCcvKkmlyFr8fFn2UkUAW3UVvk9bImV_RizWu2OTqvdN-hdlB27Otc-TaC8Iy20ttZsBk2Jaq3HfhVtngmDv60cZ3pYlnsKIaXAXp1kVygu_mJQ4jRPyNIu-bQreBQKL7SKVrT281nGZEp7eAjqtVVoN6k8oDDSIZ-gWXzILlOk7DdNL2PQkHhXHU3CLdPIDO9PVKligee0JrOtRQ8b1vEh29xMgX89OU164dZHdi9-on2l7SYwx4cvTB9b5pneuj7YDVdWKB9L3ScoBWhhS1XfK19qf-iHCkjvvGNLSsAbQKUvB2aBVIHa7590bN-_5ic8Xtqs7DLCYpm5IL_YUbpo8',\n      deadlineHeight: 1106620,\n      block: 1106620,\n      validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n      signature:\n        '0x9297e6c9e8abf5dcc3f2c748a7fe4dc5d44aeeb8234ba7cf278398be8fc485094a10968b5c77a458beee54318247232aa488469769c9ecb0dec5e3327cbc04e81c',\n      signedByDelegate: true,\n      signatureDeadline: 1674747935,\n      typedData: {\n        types: {\n          MirrorWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'profileIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'pubIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'referenceModuleData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        value: {\n          profileId: '0x18',\n          profileIdPointed: '0x18',\n          pubIdPointed: '0x3a',\n          referenceModuleData: '0x',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          referenceModuleInitData: '0x',\n          nonce: 0,\n          deadline: 1674747935,\n        },\n      },\n      blockHash: '0x4ea2497bdf0674b82ef6f643794f91faba5c7689a9755c17b03866b91809ed32',\n      blockNumber: 31435040,\n      blockTimestamp: 1674747935,\n    },\n    pointer: {\n      location: 'ar://hyuv0DRsJIUtZq4Vhv3FS5UlUbjp5FKnLC-P1fhtLDA',\n      type: DAPublicationPointerType.ON_DA,\n    },\n  },\n  publicationId: '0x18-0x3a-DA-6534728f',\n  event: {\n    profileId: '0x18',\n    pubId: '0x3a',\n    profileIdPointed: '0x18',\n    pubIdPointed: '0x3a',\n    referenceModuleData: '0x',\n    referenceModule: '0x0000000000000000000000000000000000000000',\n    referenceModuleReturnData: '0x',\n    timestamp: 1674747935,\n  },\n};\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/mocks/mirror/mirror-created-without-delegate-comment-arweave-response.mock.ts",
    "content": "import { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { MomokaProvider } from '../../../data-availability-models/data-availability-provider';\nimport { CreateMirrorV1EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport {\n  DAPublicationPointerType,\n  DAStructurePublication,\n} from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAMirrorCreatedEventEmittedResponse } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\n\nexport const mirrorCreatedWithoutDelegateCommentArweaveResponse: DAStructurePublication<\n  DAMirrorCreatedEventEmittedResponse,\n  CreateMirrorV1EIP712TypedData\n> = {\n  signature:\n    '0x9a80809f6db6f28a96e14ec588125ceecf4824a65c2e7ca748f8de7fd1531c696cb119eb5027fc09d02c8eb64700e8d470302c328780a12767da3696d69d46d81c',\n  dataAvailabilityId: 'b812eb36-30d8-4657-bd42-b239621b8696',\n  type: MomokaActionTypes.MIRROR_CREATED,\n  timestampProofs: {\n    type: MomokaProvider.BUNDLR,\n    hashPrefix: '1',\n    response: {\n      id: 'YfgVWKZ4jV19_IhFucPKIjjgyCJLcKfxH7Q1SUbRSWM',\n      timestamp: 1674748394302,\n      version: '1.0.0',\n      public:\n        'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n      signature:\n        'aDE6Au_oFRE3C0smwqs149GXozAds7UKy9hg6bsC2ErlEgvp3zG-zJJOYaq1AYYOOv2lb4c2IkVQjVphheTTni4WtS0WJbptEmIA6n1aRiHTGmSWa21P9JIInMh5OXGuABJTm5UzKmZfbKGzDVGquAmYc9TI5IP1G4KgY-wQwT3Tm6R61JcP39ePSNzqYUqfaHKQUZ3bxgJPNqhYN5wrhnK7_ZDzSgVPX6a5VJeWWrIooQOX5b3dA73PWlrSXWZjTJWY9TatFnG64xOIvfWcopRQmXig6cxhFVi4jCtfB9A6j6KlxbCCCYFfGeh0kegh52THNGyyajOBDWy8ik6uRfg5NswWRf0UtSJSfKfxjx9x-UpQVUIo2ILL0HjgIh_9rBu9Ydj27QBWBTcx7WVVzbuVdf6E2LOnp5ROngZyMIOxs7tEqwA6R0m33ltdLbRYXKCD8q9Q6hywSWQ2uS0SDgST5_dCGuWt1EdXRL8her4dUWw59v0vikc5Mki1ypJuocpvTqARDKelojhmTdTlllvTJSGofsh3rmzXtntTlqdDYeWbIBUb8Rf6rZR3pXbtMcCpxQI2jbaDbzB130UBYWxKqCzd9uJe4phw5Fwe9vXoMrqRjmm5c9CzM2rJdOlF26emagFyvZYaJwrzEInpPQ_ijxuPd0KmNx8dnIcc12g',\n      deadlineHeight: 1106623,\n      block: 1106623,\n      validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n      signature:\n        '0x2c5dd1fd96b4ca5ded1b1469b84b462b83508a91c6ed0ee13f819e7c642e20287be5c4f64388d3864d3936a670292be170e0755c7e8cdc667185eb1ae6cb0e291b',\n      signedByDelegate: false,\n      signatureDeadline: 1674748393,\n      typedData: {\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        types: {\n          MirrorWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'profileIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'pubIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'referenceModuleData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        value: {\n          profileId: '0x18',\n          profileIdPointed: '0x18',\n          pubIdPointed: '0x3a',\n          referenceModuleData: '0x',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          referenceModuleInitData: '0x',\n          deadline: 1674748393,\n          nonce: 243,\n        },\n      },\n      blockHash: '0x295c6ee6f57c1d71b60a1054f09462aa65bcc8b76c4158069991355455cf3724',\n      blockNumber: 31435254,\n      blockTimestamp: 1674748393,\n    },\n    pointer: {\n      location: 'ar://lPz6ZB0Ie19UbQ8qPqAH0-mT7Wi1A1P34bkvx3QmVu0',\n      type: DAPublicationPointerType.ON_DA,\n    },\n  },\n  publicationId: '0x18-0x3a-DA-b812eb36',\n  event: {\n    profileId: '0x18',\n    pubId: '0x3a',\n    profileIdPointed: '0x18',\n    pubIdPointed: '0x3a',\n    referenceModuleData: '0x',\n    referenceModule: '0x0000000000000000000000000000000000000000',\n    referenceModuleReturnData: '0x',\n    timestamp: 1674748393,\n  },\n};\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/mocks/mirror/mirror-created-without-delegate-post-arweave-response.mock.ts",
    "content": "import { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { MomokaProvider } from '../../../data-availability-models/data-availability-provider';\nimport { CreateMirrorV1EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport {\n  DAPublicationPointerType,\n  DAStructurePublication,\n} from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAMirrorCreatedEventEmittedResponse } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\n\nexport const mirrorCreatedWithoutDelegatePostArweaveResponse: DAStructurePublication<\n  DAMirrorCreatedEventEmittedResponse,\n  CreateMirrorV1EIP712TypedData\n> = {\n  signature:\n    '0x1683ef107f09a291ebbe8f4bfc4f628ff9be10f661d0d18048c31a8b1ca981d948ef12c591e5d762e952bc287e57838b031a6451f2b8a58cfc5cedb565c742661b',\n  dataAvailabilityId: '538ca9c4-682b-41d2-9b8a-52ede43728d7',\n  type: MomokaActionTypes.MIRROR_CREATED,\n  timestampProofs: {\n    type: MomokaProvider.BUNDLR,\n    hashPrefix: '1',\n    response: {\n      id: 'zdkCXuVzawg3KipWCRVK2fo-yIUoj5IMuIYyFPGA55o',\n      timestamp: 1674748125246,\n      version: '1.0.0',\n      public:\n        'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n      signature:\n        'IJjhzO0D4ioq9Gc0mghnxvOIkrZdmrqkc_UpMkL9R-qulzvkZ_LY4QRQxP-rNAm-ZIoN3Jep9zefjTaRRvU6mhc6hKZaMWC4XvWW_IXl5TZH1eOfq0JENjoRoZ75IdwicJXtc9c7obeNs84hXqlNHJXUoQfC2mEjkqiRpK_Vz43Hxn-3ZkrNvNEM1cpbl5hJU3UP0iCQnJQPiTgiojnhTBgRoIEpLQBFdoF1IRXUH4J4TBCMoX5MzG5PUj_FJkJiYX_SM0iaiDi0y-6-IsvOu1o32UWVgmDa-PbTrd6kGuDdd3Ys4HHyjGbS4NGkbu-coMW7RdkCegowgrXvzDoVxG0pVKoMK7ndOfZJJlud3jonqcDDI0vESSVdt_DDMOjkqdHiyWdVWcDlS0TnToIdwuOgaHDgpoqFjPUd5GwE40QFix6QflbxfcFqleru9eDY4_hufxMYEWK3DiSN6QIe6jQg6-9ZLFvD4Chr_bxL48UkfwDx-Y7EZo5tb6uzwzEqAfXEb5ITyzVrEgo1sXEDKKkkNQ7C5Hq2mryWKRXHUtXkKErI1P_bNRp2GXumO30uwZfpsMcAtFPCsPMnm1j4aqhFjcpVk9HpFPa6DcCuX6U8T3MODbJbNPxFc_Pdt5wcLo6EcLEnnQTIvQEIj_aQvh__rh79d6XHckI1TL-9gAM',\n      deadlineHeight: 1106621,\n      block: 1106621,\n      validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n      signature:\n        '0x59cb0d34ef20e93e4073cadec0d05eb8ef9a6af4b55d7ddea099666f83509d193e554c4149856ddb36ac3a4601c7f4e12fc413e016b6d4b314846eb3222b2e9b1b',\n      signedByDelegate: false,\n      signatureDeadline: 1674748123,\n      typedData: {\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        types: {\n          MirrorWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'profileIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'pubIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'referenceModuleData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        value: {\n          profileId: '0x18',\n          profileIdPointed: '0x18',\n          pubIdPointed: '0x3a',\n          referenceModuleData: '0x',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          referenceModuleInitData: '0x',\n          deadline: 1674748123,\n          nonce: 243,\n        },\n      },\n      blockHash: '0x0fb258841acaf93b998028bfc7296b840a80cdc76ffd999d5101bc72cf2daf78',\n      blockNumber: 31435129,\n      blockTimestamp: 1674748123,\n    },\n    pointer: {\n      location: 'ar://ff9CtLecXt1HBFBR-SoRz8tLjPjBo8gxbmy7kmFpJl4',\n      type: DAPublicationPointerType.ON_DA,\n    },\n  },\n  publicationId: '0x18-0x3a-DA-538ca9c4',\n  event: {\n    profileId: '0x18',\n    pubId: '0x3a',\n    profileIdPointed: '0x18',\n    pubIdPointed: '0x3a',\n    referenceModuleData: '0x',\n    referenceModule: '0x0000000000000000000000000000000000000000',\n    referenceModuleReturnData: '0x',\n    timestamp: 1674748123,\n  },\n};\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/mocks/post/post-created-delegate-arweave-response.mock.ts",
    "content": "import { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { MomokaProvider } from '../../../data-availability-models/data-availability-provider';\nimport { CreatePostV1EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport { DAStructurePublication } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAPostCreatedEventEmittedResponse } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\n\nexport const postCreatedDelegateArweaveResponse: DAStructurePublication<\n  DAPostCreatedEventEmittedResponse,\n  CreatePostV1EIP712TypedData\n> = {\n  signature:\n    '0x42c63a72de7442c809a8db23f9994ff3c57b5a2101e8512102ea1238a78181903513c675ea35bd2e912f1a258dabe631fd22b3609e9edcd1a9df799c0ebc03621c',\n  dataAvailabilityId: '68d40ddd-a9ae-4843-b9e8-50ed55e27488',\n  type: MomokaActionTypes.POST_CREATED,\n  timestampProofs: {\n    type: MomokaProvider.BUNDLR,\n    hashPrefix: '1',\n    response: {\n      id: 'DMGovTZKvZkWCbhgm1mRNi3MrjMl9lJtQ-0ReW4j7Wc',\n      timestamp: 1674650243344,\n      version: '1.0.0',\n      public:\n        'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n      signature:\n        'bbrYlPfRjsAQiAlkv8ghwHp5_uf66jMZ6ovr2sCxJSYSY57wr64K4iJ0DF097TxvZFPaP-JvqAejXWYZ1QAi48BITZpv8dtiVpYG9-eE03dvx-FcxuGGAGN4K9KwGbeMauipOW4yLd_oRH4OZHIFcCJn_XU5oSGnV0GlopG3GkQy095Z9a7DaDZEEFc5-r6wVnsWrLuqDWmhRxfu2RcSripf5YSAELa03LX6-Hn3yGKi3aAA3xz90d2irLmj3Ib-qVPMWez0NwacsSecEQ_zR3sudsWn3T6KG5DxRGr8sCvx-5S9Mbg5YEPQx2GVgL7oPYxlQD3y1XNhupv3eB-9mfGq4AvvC2vD9xW-q7zgCl5gKZSnVffxrhmo4gU_pq0TP6ES-d-6Npk8szhjSFxgV_lpWbHfY0l2wr9WLQ87FcP5l4cDXNwBl62hR9w11vz86TzxIA-NWSYEjkAoge6-yfOK2n8ln0UOURMdumSh6kPPFfASkQdi3geBJuCoUIcuXScaExhiHrbUantrfuqd6o7hH-_GtYr1690V7zRS40Ie5vfrQZ-2WiwNFuNUdOnLqL-f4ftTXMvd3D8_QBSUuIpkZt4lWL6LxdEbw9niCzpN-yfCS4G22UFZn8MaGLKY2am5GdQ2DHceYFd2QhYC9-_7GZklobZwWP__oAn3_gc',\n      block: 1105854,\n      deadlineHeight: 1105854,\n      validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n      signature:\n        '0x9e777c60c7745be9412795c0deae73d26844f2ba0b80672c31b554d8f204103f2c59769290ff436cd65cc9b4632f2a168e598222fc6a212ccbc62b6525ca73231b',\n      signedByDelegate: true,\n      signatureDeadline: 1674650240,\n      typedData: {\n        types: {\n          PostWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'contentURI',\n              type: 'string',\n            },\n            {\n              name: 'collectModule',\n              type: 'address',\n            },\n            {\n              name: 'collectModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        value: {\n          profileId: '0x18',\n          contentURI: 'ar://CB1hvV_8Wxx-QkKyhYGheSCrXfr-W9TObXXDuU32p5k',\n          collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n          collectModuleInitData: '0x',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          referenceModuleInitData: '0x',\n          nonce: 0,\n          deadline: 1674650240,\n        },\n      },\n      blockHash: '0x10953c796b043fac60c8758fa68190aaebe6e0752fb42796fa832e67dccadbd0',\n      blockNumber: 31389215,\n      blockTimestamp: 1674650240,\n    },\n    pointer: null,\n  },\n  publicationId: '0x18-0x3a-DA-68d40ddd',\n  event: {\n    profileId: '0x18',\n    pubId: '0x3a',\n    contentURI: 'ar://CB1hvV_8Wxx-QkKyhYGheSCrXfr-W9TObXXDuU32p5k',\n    collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n    collectModuleReturnData: '0x',\n    referenceModule: '0x0000000000000000000000000000000000000000',\n    referenceModuleReturnData: '0x',\n    timestamp: 1674650240,\n  },\n};\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/mocks/post/post-created-without-delegate-arweave-response.mock.ts",
    "content": "import { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { MomokaProvider } from '../../../data-availability-models/data-availability-provider';\nimport { CreatePostV1EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport { DAStructurePublication } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAPostCreatedEventEmittedResponse } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\n\nexport const postCreatedWithoutDelegateArweaveResponse: DAStructurePublication<\n  DAPostCreatedEventEmittedResponse,\n  CreatePostV1EIP712TypedData\n> = {\n  signature:\n    '0x87866d620636f62aa3930d8c48be37dac77f96f30a9e06748491934fef75e7884a193d59fc486da3ea35f991bbd37a04ea4997e47f191d626ad2b601e3cc57a71c',\n  dataAvailabilityId: '951a2a24-46fd-4306-8c31-46a8318a905e',\n  type: MomokaActionTypes.POST_CREATED,\n  timestampProofs: {\n    type: MomokaProvider.BUNDLR,\n    hashPrefix: '1',\n    response: {\n      id: 'f7_YMkEqiALN9PCtK5LXxFDlc3EEi20-DWl57KxDMbw',\n      timestamp: 1674736509185,\n      version: '1.0.0',\n      public:\n        'sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek',\n      signature:\n        'Requv25_byuhK_k0JPz2tjKLhmqUv1XGt4My88utf8AHpl8awJKPMUQV3LJIQABMXf9ZsM2RZNiPhKEilkefGD-fTqkZZI5ybHooP8hc-lx2mAdM0XfCw-SC-yhdDU3OoOat7bwVy0HvOJm8xc6HpqgdbnTotX3LuPAo_xEV5GxrB5giK1IY8ZBJEsIjZw6okSzEStfmm94zAG44SmtTDXJk0IpeBpQiiZks63quZkPETGR9nfYl9-5D4UjQZHsx1eqV_9Pa4vYMOnTXD5LB8ysi2C576QjJAFICEZtRF2rXyZm1yfWBY8ODrnoZx-RBB5pqAwqrwA4DBI_UBHmbB7lL_3DK4911bZbC03T1KUw5QZn6eWjnoyxIv_UG9B3Bht0UDPIgGXA2tKeUsdrrh2JPAImZIYXEhC5ZWqn-K4TZa586sGwpQVfHFvCuCA-9X6GspXKDqlqbys6sZk70OOhM4827JIs9dw_Hw8rwsPsGIJjP99x2iOnyH8FQynbW8TCnGQcsO7Xevj-1PGnIAsXqQO6E9_NkYAf8LSfsilY63ZhVNPgLnSS2BAR-28SpHW4GjXtN_nVzE1CoLmL3nczMqHTiZ-xalo_enYg0Ydx-ZqHF7cPrB5rQmR_uB_7zPKK5WgStxwVjHRBJ8MLxmW0Sylzf9K6IwwFy50klQHY',\n      deadlineHeight: 1106524,\n      block: 1106524,\n      validatorSignatures: [],\n    },\n  },\n  chainProofs: {\n    thisPublication: {\n      signature:\n        '0xa3a969bd1ecdf7ca416340b513fd751df446b922809bd05f25509a98223b69594e4d0e5c27ce01111f80dd2df8ffd5f1af75bd6d663f55c4186ef773da2168ac1c',\n      signedByDelegate: false,\n      signatureDeadline: 1674736509,\n      typedData: {\n        types: {\n          PostWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'contentURI',\n              type: 'string',\n            },\n            {\n              name: 'collectModule',\n              type: 'address',\n            },\n            {\n              name: 'collectModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        value: {\n          profileId: '0x18',\n          contentURI: 'ar://NKrOBI6zMU4mnptAGYvirARSvBAU-nkCITQ5-LZkEco',\n          collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n          collectModuleInitData: '0x',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          referenceModuleInitData: '0x',\n          nonce: 243,\n          deadline: 1674736509,\n        },\n      },\n      blockHash: '0x43f670549e740c8b2b7b56967b8a24a546b734c83e05ba20a515faddddc7c345',\n      blockNumber: 31429670,\n      blockTimestamp: 1674736509,\n    },\n    pointer: null,\n  },\n  publicationId: '0x18-0x3a-DA-951a2a24',\n  event: {\n    profileId: '0x18',\n    pubId: '0x3a',\n    contentURI: 'ar://NKrOBI6zMU4mnptAGYvirARSvBAU-nkCITQ5-LZkEco',\n    collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n    collectModuleReturnData: '0x',\n    referenceModule: '0x0000000000000000000000000000000000000000',\n    referenceModuleReturnData: '0x',\n    timestamp: 1674736509,\n  },\n};\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/mocks/shared.mock.ts",
    "content": "import {\n  Deployment,\n  Environment,\n  EthereumNode,\n  MomokaValidatorError,\n  TxValidatedResult,\n} from '../..';\nimport { checkDAProof } from '../../client';\nimport { getParamOrExit } from '../../common/helpers';\nimport { PromiseWithContextResult } from '../../data-availability-models/da-result';\nimport {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../../data-availability-models/publications/data-availability-structure-publication';\nimport * as getBundlrByIdAPIDefault from '../../input-output/bundlr/get-bundlr-by-id.api';\nimport * as database from '../../input-output/db';\nimport * as submittors from '../../submitters';\nimport { postCreatedDelegateArweaveResponse } from './post/post-created-delegate-arweave-response.mock';\n\nexport const mockGetTxDb = database.getTxDb as jest.MockedFunction<typeof database.getTxDb>;\nmockGetTxDb.mockImplementation(async () => null);\n\nexport const mockhasSignatureBeenUsedBeforeDb =\n  database.hasSignatureBeenUsedBeforeDb as jest.MockedFunction<\n    typeof database.hasSignatureBeenUsedBeforeDb\n  >;\nmockhasSignatureBeenUsedBeforeDb.mockImplementation(async () => false);\n\nexport const mockGetDAPublicationByIdAPI =\n  getBundlrByIdAPIDefault.getBundlrByIdAPI as jest.MockedFunction<\n    typeof getBundlrByIdAPIDefault.getBundlrByIdAPI\n  >;\n\nexport const mockImpl__NO_SIGNATURE_SUBMITTER = (\n  baseMock: DAStructurePublication<DAEventType, PublicationTypedData>\n): void => {\n  mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n    return {\n      ...baseMock,\n      signature: undefined,\n    };\n  });\n};\n\nexport const mockImpl__TIMESTAMP_PROOF_INVALID_SIGNATURE = (\n  baseMock: DAStructurePublication<DAEventType, PublicationTypedData>\n): void => {\n  mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n    return {\n      ...baseMock,\n      timestampProofs: {\n        response: {\n          ...baseMock.timestampProofs.response,\n          timestamp: 123456789,\n        },\n      },\n    };\n  });\n};\n\nexport const mockImpl__TIMESTAMP_PROOF_NOT_SUBMITTER = (): void => {\n  mockIsValidSubmitter.mockImplementationOnce(() => false);\n};\n\nexport const mockImpl__INVALID_EVENT_TIMESTAMP = (\n  baseMock: DAStructurePublication<DAEventType, PublicationTypedData>\n): void => {\n  mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n    return {\n      ...baseMock,\n      event: {\n        ...baseMock.event,\n        timestamp: 111,\n      },\n    };\n  });\n};\n\nexport const mockImpl__INVALID_POINTER_SET = (\n  baseMock: DAStructurePublication<DAEventType, PublicationTypedData>,\n  pointer: unknown\n): void => {\n  mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n    return {\n      ...baseMock,\n      chainProofs: {\n        ...baseMock.chainProofs,\n        pointer: pointer,\n      },\n    };\n  });\n};\n\nexport const mockImpl__SIMULATION_FAILED_BAD_PROFILE_ID = (\n  baseMock: DAStructurePublication<DAEventType, PublicationTypedData>\n): void => {\n  mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n    return {\n      ...baseMock,\n      chainProofs: {\n        ...baseMock.chainProofs,\n        thisPublication: {\n          ...baseMock.chainProofs.thisPublication,\n          typedData: {\n            ...baseMock.chainProofs.thisPublication.typedData,\n            value: {\n              ...baseMock.chainProofs.thisPublication.typedData.value,\n              profileId: '0x02',\n            },\n          },\n        },\n      },\n    };\n  });\n};\n\nexport const mockImpl__INVALID_FORMATTED_TYPED_DATA = (\n  baseMock: DAStructurePublication<DAEventType, PublicationTypedData>\n): void => {\n  mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n    return {\n      ...baseMock,\n      chainProofs: {\n        ...baseMock.chainProofs,\n        thisPublication: {\n          ...baseMock.chainProofs.thisPublication,\n          typedData: {\n            ...baseMock.chainProofs.thisPublication.typedData,\n            value: {\n              ...baseMock.chainProofs.thisPublication.typedData.value,\n              referenceModule: '0x0000000000000000000000000000000000000',\n            },\n          },\n        },\n      },\n    };\n  });\n};\n\nexport const mockGetSubmitters = submittors.getSubmitters as jest.MockedFunction<\n  typeof submittors.getSubmitters\n>;\nmockGetSubmitters.mockImplementation(() => ['0x886Bb211aC324dAF3744b2AB0eF20C0aCf73eA59']);\n\nexport const mockIsValidSubmitter = submittors.isValidSubmitter as jest.MockedFunction<\n  typeof submittors.isValidSubmitter\n>;\nmockIsValidSubmitter.mockImplementation(() => true);\n\nconst ethereumNode: EthereumNode = {\n  environment: getParamOrExit('ETHEREUM_NETWORK') as Environment,\n  nodeUrl: getParamOrExit('NODE_URL'),\n  deployment: Deployment.STAGING,\n};\n\nexport const callCheckDAProof = (): PromiseWithContextResult<\n  void | DAStructurePublication<DAEventType, PublicationTypedData>,\n  DAStructurePublication<DAEventType, PublicationTypedData>\n> => {\n  return checkDAProof('mocked_tx_id', ethereumNode, {\n    log: jest.fn(),\n    byPassDb: false,\n    verifyPointer: true,\n  });\n};\n\nexport const checkAndValidateDAProof = async (\n  expectedError: MomokaValidatorError\n): Promise<void> => {\n  const result = await callCheckDAProof();\n  expect(result.isFailure()).toBe(true);\n  if (result.isFailure()) {\n    expect(result.failure).toEqual(expectedError);\n  }\n};\n\nexport const random = (): string => (Math.random() + 1).toString(36).substring(7);\n\nexport const mockTxValidationResult: TxValidatedResult = {\n  success: true,\n  proofTxId: random(),\n  dataAvailabilityResult: postCreatedDelegateArweaveResponse,\n};\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/post.e2e.test.ts",
    "content": "// apply mocks!\njest.setTimeout(30000);\njest.mock('../input-output/db');\njest.mock('../input-output/bundlr/get-bundlr-by-id.api');\njest.mock('../submitters');\n\nimport { deepClone } from '../common/helpers';\nimport { MomokaValidatorError } from '../data-availability-models/validator-errors';\nimport { postCreatedDelegateArweaveResponse } from './mocks/post/post-created-delegate-arweave-response.mock';\nimport { postCreatedWithoutDelegateArweaveResponse } from './mocks/post/post-created-without-delegate-arweave-response.mock';\nimport * as sharedMocks from './mocks/shared.mock';\nimport { mockTxValidationResult } from './mocks/shared.mock';\n\ndescribe('post', () => {\n  describe('with delegate', () => {\n    let baseMock = postCreatedDelegateArweaveResponse;\n\n    beforeEach(() => {\n      baseMock = postCreatedDelegateArweaveResponse;\n      sharedMocks.mockGetDAPublicationByIdAPI.mockImplementation(async () =>\n        deepClone(postCreatedDelegateArweaveResponse)\n      );\n    });\n\n    describe('should return success when', () => {\n      test('signed by delegate is true', async () => {\n        expect(baseMock.chainProofs.thisPublication.signedByDelegate).toBe(true);\n      });\n\n      test('txExists in the db already', async () => {\n        sharedMocks.mockGetTxDb.mockImplementationOnce(async () => mockTxValidationResult);\n        const result = await sharedMocks.callCheckDAProof();\n        expect(result.isSuccess()).toBe(true);\n      });\n\n      test('tx is valid and passes all the simulation checks', async () => {\n        const result = await sharedMocks.callCheckDAProof();\n        expect(result.isSuccess()).toBe(true);\n      });\n    });\n\n    describe('should return failure when', () => {\n      test('NO_SIGNATURE_SUBMITTER', async () => {\n        sharedMocks.mockImpl__NO_SIGNATURE_SUBMITTER(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NO_SIGNATURE_SUBMITTER);\n      });\n\n      xtest('INVALID_SIGNATURE_SUBMITTER', async () => {\n        sharedMocks.mockIsValidSubmitter.mockImplementationOnce(() => false);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_SIGNATURE_SUBMITTER);\n      });\n\n      test('TIMESTAMP_PROOF_INVALID_SIGNATURE', async () => {\n        sharedMocks.mockImpl__TIMESTAMP_PROOF_INVALID_SIGNATURE(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SIGNATURE\n        );\n      });\n\n      test('TIMESTAMP_PROOF_NOT_SUBMITTER', async () => {\n        sharedMocks.mockImpl__TIMESTAMP_PROOF_NOT_SUBMITTER();\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.TIMESTAMP_PROOF_NOT_SUBMITTER\n        );\n      });\n\n      test('INVALID_EVENT_TIMESTAMP', async () => {\n        sharedMocks.mockImpl__INVALID_EVENT_TIMESTAMP(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_EVENT_TIMESTAMP);\n      });\n\n      xtest('NOT_CLOSEST_BLOCK', async () => {\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NOT_CLOSEST_BLOCK);\n      });\n\n      test('INVALID_POINTER_SET_NOT_NEEDED', async () => {\n        sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, 'mocked');\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.INVALID_POINTER_SET_NOT_NEEDED\n        );\n      });\n\n      test('SIMULATION_FAILED - trying to submit a tx with a profile id not owned', async () => {\n        sharedMocks.mockImpl__SIMULATION_FAILED_BAD_PROFILE_ID(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.SIMULATION_FAILED);\n      });\n\n      test('INVALID_FORMATTED_TYPED_DATA', async () => {\n        sharedMocks.mockImpl__INVALID_FORMATTED_TYPED_DATA(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA\n        );\n      });\n\n      test('EVENT_MISMATCH - pub id does not match simulated result', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              pubId: '0x000000000000002',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - profile id does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              profileId: '0x02',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - contentURI does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              contentURI: '__mocked_content_uri__',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - collectModule does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              collectModule: '0x0000000000000000000000000000000000000',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - collectModuleReturnData is not empty bytes', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              collectModuleReturnData: 'not_empty_bytes',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - referenceModule does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              referenceModule: '0x0000000000000000000000000000000000001',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - referenceModuleReturnData is not empty bytes', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              referenceModuleReturnData: 'not_empty_bytes',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      xtest('SIMULATION_NODE_COULD_NOT_RUN', async () => {});\n\n      xtest('UNKNOWN', () => {});\n    });\n  });\n\n  describe('without delegate', () => {\n    let baseMock = postCreatedWithoutDelegateArweaveResponse;\n\n    beforeEach(() => {\n      baseMock = postCreatedWithoutDelegateArweaveResponse;\n      sharedMocks.mockGetDAPublicationByIdAPI.mockImplementation(async () =>\n        deepClone(postCreatedWithoutDelegateArweaveResponse)\n      );\n    });\n\n    describe('should return success when', () => {\n      test('signed by delegate is false', () => {\n        expect(baseMock.chainProofs.thisPublication.signedByDelegate).toBe(false);\n      });\n\n      test('txExists in the db already', async () => {\n        sharedMocks.mockGetTxDb.mockImplementationOnce(async () => mockTxValidationResult);\n        const result = await sharedMocks.callCheckDAProof();\n        expect(result.isSuccess()).toBe(true);\n      });\n\n      test('tx is valid and passes all the simulation checks', async () => {\n        const result = await sharedMocks.callCheckDAProof();\n        expect(result.isSuccess()).toBe(true);\n      });\n    });\n\n    describe('should return failure when', () => {\n      test('NO_SIGNATURE_SUBMITTER', async () => {\n        sharedMocks.mockImpl__NO_SIGNATURE_SUBMITTER(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NO_SIGNATURE_SUBMITTER);\n      });\n\n      xtest('INVALID_SIGNATURE_SUBMITTER', async () => {\n        sharedMocks.mockIsValidSubmitter.mockImplementationOnce(() => false);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_SIGNATURE_SUBMITTER);\n      });\n\n      test('TIMESTAMP_PROOF_INVALID_SIGNATURE', async () => {\n        sharedMocks.mockImpl__TIMESTAMP_PROOF_INVALID_SIGNATURE(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SIGNATURE\n        );\n      });\n\n      test('TIMESTAMP_PROOF_NOT_SUBMITTER', async () => {\n        sharedMocks.mockImpl__TIMESTAMP_PROOF_NOT_SUBMITTER();\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.TIMESTAMP_PROOF_NOT_SUBMITTER\n        );\n      });\n\n      test('INVALID_EVENT_TIMESTAMP', async () => {\n        sharedMocks.mockImpl__INVALID_EVENT_TIMESTAMP(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.INVALID_EVENT_TIMESTAMP);\n      });\n\n      xtest('NOT_CLOSEST_BLOCK', async () => {\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.NOT_CLOSEST_BLOCK);\n      });\n\n      test('INVALID_POINTER_SET_NOT_NEEDED', async () => {\n        sharedMocks.mockImpl__INVALID_POINTER_SET(baseMock, 'mocked');\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.INVALID_POINTER_SET_NOT_NEEDED\n        );\n      });\n\n      test('SIMULATION_FAILED - trying to submit a tx with a profile id not owned', async () => {\n        sharedMocks.mockImpl__SIMULATION_FAILED_BAD_PROFILE_ID(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.SIMULATION_FAILED);\n      });\n\n      test('INVALID_FORMATTED_TYPED_DATA', async () => {\n        sharedMocks.mockImpl__INVALID_FORMATTED_TYPED_DATA(baseMock);\n\n        await sharedMocks.checkAndValidateDAProof(\n          MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA\n        );\n      });\n\n      test('EVENT_MISMATCH - pub id does not match simulated result', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              pubId: '0x000000000000002',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - profile id does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              profileId: '0x02',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - contentURI does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              contentURI: '__mocked_content_uri__',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - collectModule does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              collectModule: '0x0000000000000000000000000000000000000',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - collectModuleReturnData is not empty bytes', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              collectModuleReturnData: 'not_empty_bytes',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - referenceModule does not match typed data', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              referenceModule: '0x0000000000000000000000000000000000001',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      test('EVENT_MISMATCH - referenceModuleReturnData is not empty bytes', async () => {\n        sharedMocks.mockGetDAPublicationByIdAPI.mockImplementationOnce(async () => {\n          return {\n            ...baseMock,\n            event: {\n              ...baseMock.event,\n              referenceModuleReturnData: 'not_empty_bytes',\n            },\n          };\n        });\n\n        await sharedMocks.checkAndValidateDAProof(MomokaValidatorError.EVENT_MISMATCH);\n      });\n\n      xtest('SIMULATION_NODE_COULD_NOT_RUN', async () => {});\n\n      xtest('UNKNOWN', () => {});\n    });\n  });\n});\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/publications/publication.base.test.ts",
    "content": "import { whoSignedTypedData } from '../../proofs/publications/publication.base';\n\ndescribe('publication base', () => {\n  describe('whoSignedTypedData', () => {\n    test('should return back correct address', async () => {\n      const typedData = {\n        types: {\n          CommentWithSig: [\n            {\n              name: 'profileId',\n              type: 'uint256',\n            },\n            {\n              name: 'contentURI',\n              type: 'string',\n            },\n            {\n              name: 'profileIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'pubIdPointed',\n              type: 'uint256',\n            },\n            {\n              name: 'referenceModuleData',\n              type: 'bytes',\n            },\n            {\n              name: 'collectModule',\n              type: 'address',\n            },\n            {\n              name: 'collectModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'referenceModule',\n              type: 'address',\n            },\n            {\n              name: 'referenceModuleInitData',\n              type: 'bytes',\n            },\n            {\n              name: 'nonce',\n              type: 'uint256',\n            },\n            {\n              name: 'deadline',\n              type: 'uint256',\n            },\n          ],\n        },\n        domain: {\n          name: 'Lens Protocol Profiles',\n          version: '1',\n          chainId: 80001,\n          verifyingContract: '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82',\n        },\n        value: {\n          profileId: '0x18',\n          profileIdPointed: '0x18',\n          pubIdPointed: '0x3a',\n          contentURI: 'ar://IZHY6SC77JtgMpuKmzbecgKV9HACdMtYb6a0lY1xL14',\n          referenceModule: '0x0000000000000000000000000000000000000000',\n          collectModule: '0x5E70fFD2C6D04d65C3abeBa64E93082cfA348dF8',\n          collectModuleInitData: '0x',\n          referenceModuleInitData: '0x',\n          referenceModuleData: '0x',\n          nonce: 243,\n          deadline: 1674751411,\n        },\n      };\n\n      const result = await whoSignedTypedData(\n        typedData.domain,\n        typedData.types,\n        typedData.value,\n        '0x56b1108c5c15aa3344fe87aa0a5b2d827625de8a7283e5cdb21088e30d49cd4203088a336bc9c0fac5cca0a84af84b7227be24e0bef55ece423f25015e807cd71b'\n      );\n\n      expect(result.isSuccess()).toEqual(true);\n      if (result.isSuccess()) {\n        expect(result.successResult).toEqual('0xD8c789626CDb461ec9347f26DDbA98F9383aa457');\n      }\n    });\n  });\n});\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/random.test.ts",
    "content": "import { getBundlrByIdAPI } from '../input-output/bundlr/get-bundlr-by-id.api';\nimport { LibCurlProvider } from '../input-output/lib-curl-provider';\n\ndescribe('random', () => {\n  it('getBundlrByIdAPI', async () => {\n    const txId = 'oWnpbkMpnGxMMnFDxnwxCQVhEK55jJeuiyLGUv2bSrk';\n    await getBundlrByIdAPI(txId, { provider: new LibCurlProvider() });\n  });\n});\n"
  },
  {
    "path": "momoka-node/src/__TESTS__/submitters.test.ts",
    "content": "import { Environment } from '../common/environment';\nimport { getParamOrExit } from '../common/helpers';\nimport { EthereumNode } from '../evm/ethereum';\nimport { getOwnerOfTransactionAPI } from '../input-output/bundlr/get-owner-of-transaction.api';\n\nimport { getSubmitters, isValidSubmitter } from '../submitters';\n\njest.mock('../input-output/bundlr/get-owner-of-transaction.api');\n\nexport const mockGetOwnerOfTransactionAPI = getOwnerOfTransactionAPI as jest.MockedFunction<\n  typeof getOwnerOfTransactionAPI\n>;\n\nconst ethereumNode: EthereumNode = {\n  environment: getParamOrExit('ETHEREUM_NETWORK') as Environment,\n  nodeUrl: getParamOrExit('NODE_URL'),\n};\n\ndescribe('submitters', () => {\n  describe('getSubmitters', () => {\n    it('should return 1 submitter', () => {\n      expect(getSubmitters(ethereumNode.environment)).toHaveLength(1);\n    });\n  });\n\n  describe('isValidSubmitter', () => {\n    it('should return false with an invalid submitter', () => {\n      expect(isValidSubmitter(ethereumNode.environment, '111')).toEqual(false);\n    });\n\n    it('should return true with an valid submitter', () => {\n      const submitter = getSubmitters(ethereumNode.environment)[0];\n      expect(isValidSubmitter(ethereumNode.environment, submitter)).toEqual(true);\n    });\n  });\n});\n"
  },
  {
    "path": "momoka-node/src/bin/cli.ts",
    "content": "#!/usr/bin/env node\n\nimport yargs from 'yargs';\nimport { Deployment, Environment } from '../common/environment';\nimport { turnedOffExperimentalWarning } from '../common/helpers';\nimport { startDAVerifierNode } from '../watchers/verifier.watcher';\n\nturnedOffExperimentalWarning();\n\ninterface ProgramOptions {\n  command: string;\n  subcommands: string[];\n  options: { [key: string]: string };\n}\n\nconst getProgramArguments = (): ProgramOptions => {\n  // tslint:disable-next-line: typedef\n  const {\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore\n    _: [command, ...subcommands],\n    ...options\n  } = yargs.argv;\n  return {\n    command,\n    options: Object.keys(options).reduce((r, v) => {\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore\n      r[v] = options[v];\n      return r;\n    }, {}),\n    subcommands,\n  };\n};\n\nconst args = getProgramArguments();\n\nconst nodeUrl = args.options.node;\nif (!nodeUrl) {\n  console.log('No node url specified');\n  process.exit(1);\n}\nconst environment = (args.options.environment as Environment) || Environment.POLYGON;\nconst deployment = (args.options.deployment as Deployment) || Deployment.PRODUCTION;\n\nconst concurrencyRaw = args.options.concurrency;\nconst concurrency = concurrencyRaw ? Number(concurrencyRaw) : 100;\n\nconst resyncRaw = args.options.resync;\nconst resync = resyncRaw === 'true';\n\nstartDAVerifierNode(\n  {\n    nodeUrl,\n    environment,\n    deployment,\n  },\n  concurrency,\n  { resync }\n).catch((error) => {\n  console.error('momoka node failed to startup', error);\n  process.exitCode = 1;\n});\n"
  },
  {
    "path": "momoka-node/src/client/axios-provider.ts",
    "content": "import axios from 'axios';\nimport { FetchProvider } from '../input-output/fetch-with-timeout';\n\nexport class AxiosProvider implements FetchProvider {\n  async get<TResponse>(url: string, { timeout }: { timeout: number }): Promise<TResponse> {\n    const response = await axios.get(url, {\n      timeout,\n    });\n\n    return response.data as TResponse;\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/client/check-da-proof-client.ts",
    "content": "import { EthereumNode } from '../evm/ethereum';\nimport {\n  CheckDASubmissionOptions,\n  getDefaultCheckDASubmissionOptions,\n} from '../proofs/models/check-da-submisson-options';\nimport { PromiseWithContextResult } from '../data-availability-models/da-result';\nimport {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../data-availability-models/publications/data-availability-structure-publication';\nimport { ClientDaProofGateway } from './client-da-proof-gateway';\nimport { DaProofChecker } from '../proofs/da-proof-checker';\nimport { ClientDaProofVerifier } from './client-da-proof-verifier';\n\nconst gateway = new ClientDaProofGateway();\nconst verifier = new ClientDaProofVerifier();\nconst checker = new DaProofChecker(verifier, gateway);\n\nexport const checkDAProof = (\n  txId: string,\n  ethereumNode: EthereumNode,\n  options: CheckDASubmissionOptions = getDefaultCheckDASubmissionOptions\n): PromiseWithContextResult<\n  DAStructurePublication<DAEventType, PublicationTypedData> | void,\n  DAStructurePublication<DAEventType, PublicationTypedData>\n> => {\n  return checker.checkDAProof(txId, ethereumNode, options);\n};\n"
  },
  {
    "path": "momoka-node/src/client/client-da-proof-gateway.ts",
    "content": "import { DATimestampProofsResponse } from '../data-availability-models/data-availability-timestamp-proofs';\nimport {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../data-availability-models/publications/data-availability-structure-publication';\nimport { BlockInfo, EthereumNode, getBlock } from '../evm/ethereum';\nimport { getBundlrByIdAPI } from '../input-output/bundlr/get-bundlr-by-id.api';\nimport { TimeoutError } from '../input-output/common';\nimport { TxValidatedResult } from '../input-output/tx-validated-results';\nimport { DAProofsGateway } from '../proofs/da-proof-checker';\nimport { AxiosProvider } from './axios-provider';\n\nexport class ClientDaProofGateway implements DAProofsGateway {\n  public getBlockRange(blockNumbers: number[], ethereumNode: EthereumNode): Promise<BlockInfo[]> {\n    return Promise.all(blockNumbers.map((blockNumber) => getBlock(blockNumber, ethereumNode)));\n  }\n\n  public getDaPublication(\n    txId: string\n  ): Promise<DAStructurePublication<DAEventType, PublicationTypedData> | TimeoutError | null> {\n    return getBundlrByIdAPI<DAStructurePublication<DAEventType, PublicationTypedData>>(txId, {\n      provider: new AxiosProvider(),\n    });\n  }\n\n  public getTimestampProofs(\n    timestampId: string\n  ): Promise<DATimestampProofsResponse | TimeoutError | null> {\n    return getBundlrByIdAPI<DATimestampProofsResponse>(timestampId, {\n      provider: new AxiosProvider(),\n    });\n  }\n\n  // No cache available in the client\n  public getTxResultFromCache(): Promise<TxValidatedResult | null> {\n    return Promise.resolve(null);\n  }\n\n  // No signature usage in the client\n  public hasSignatureBeenUsedBefore(_signature: string): Promise<boolean> {\n    return Promise.resolve(false);\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/client/client-da-proof-verifier.ts",
    "content": "import { utils } from 'ethers';\nimport Arweave from 'arweave/web';\nimport deepHash from 'arweave/web/lib/deepHash';\nimport { b64UrlToBuffer } from 'arweave/web/lib/utils';\n\nimport {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../data-availability-models/publications/data-availability-structure-publication';\nimport { deepClone } from '../common/helpers';\nimport { DAProofsVerifier } from '../proofs/da-proof-checker';\nimport { AxiosProvider } from './axios-provider';\nimport { Deployment, Environment } from '../common/environment';\nimport { LogFunctionType } from '../common/logger';\nimport { TimeoutError, TIMEOUT_ERROR } from '../input-output/common';\nimport { getOwnerOfTransactionAPI } from '../input-output/bundlr/get-owner-of-transaction.api';\nimport { isValidSubmitter } from '../submitters';\nimport { verifyReceipt } from '../proofs/utils';\n\nexport class ClientDaProofVerifier implements DAProofsVerifier {\n  extractAddress(\n    daPublication: DAStructurePublication<DAEventType, PublicationTypedData>\n  ): Promise<string> {\n    const signature = deepClone(daPublication.signature);\n\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore\n    // TODO: Is that important to remove signature from the shared object?\n    delete daPublication.signature;\n\n    return Promise.resolve(utils.verifyMessage(JSON.stringify(daPublication), signature));\n  }\n\n  verifyTimestampSignature(\n    daPublication: DAStructurePublication<DAEventType, PublicationTypedData>\n  ): Promise<boolean> {\n    return verifyReceipt(daPublication.timestampProofs.response, {\n      crypto: Arweave.crypto,\n      deepHash,\n      b64UrlToBuffer,\n      stringToBuffer: Arweave.utils.stringToBuffer,\n    });\n  }\n\n  async verifyTransactionSubmitter(\n    environment: Environment,\n    txId: string,\n    log: LogFunctionType,\n    deployment?: Deployment\n  ): Promise<boolean | TimeoutError> {\n    const owner = await getOwnerOfTransactionAPI(txId, { provider: new AxiosProvider() });\n    if (owner === TIMEOUT_ERROR) {\n      return TIMEOUT_ERROR;\n    }\n    if (!owner) {\n      return false;\n    }\n    log('owner result', owner);\n    return isValidSubmitter(environment, owner, deployment);\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/client/index.ts",
    "content": "export { Deployment, Environment } from '../common/environment';\nexport {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../data-availability-models/publications/data-availability-structure-publication';\nexport { MomokaValidatorError } from '../data-availability-models/validator-errors';\nexport { EthereumNode } from '../evm/ethereum';\nexport {\n  TxValidatedFailureResult,\n  TxValidatedResult,\n  TxValidatedSuccessResult,\n} from '../input-output/tx-validated-results';\nexport { checkDAProof } from './check-da-proof-client';\n"
  },
  {
    "path": "momoka-node/src/common/environment.ts",
    "content": "/**\n * Enum defining the supported Ethereum environments for the verifier node.\n */\nexport enum Environment {\n  POLYGON = 'POLYGON',\n  MUMBAI = 'MUMBAI',\n  AMOY = 'AMOY',\n}\n\n/**\n * Enum defining the deployment configurations for the verifier node.\n */\nexport enum Deployment {\n  PRODUCTION = 'PRODUCTION',\n  STAGING = 'STAGING',\n  LOCAL = 'LOCAL',\n}\n\n/**\n * Maps an Ethereum environment to its corresponding chain ID.\n * @param environment The Ethereum environment to map to a chain ID.\n * @returns The chain ID corresponding to the provided Ethereum environment.\n * @throws An error if the provided environment is invalid.\n */\nexport const environmentToChainId = (environment: Environment): 137 | 80001 | 80002 => {\n  switch (environment) {\n    case Environment.POLYGON:\n      return 137;\n    case Environment.MUMBAI:\n      return 80001;\n    case Environment.AMOY:\n      return 80002;\n    default:\n      throw new Error('Invalid environment');\n  }\n};\n\n/**\n * Maps an Ethereum environment to its corresponding Lens Hub contract address.\n * @param environment The Ethereum environment to map to a Lens Hub contract address.\n * @returns The Lens Hub contract address corresponding to the provided Ethereum environment.\n * @throws An error if the provided environment is invalid.\n */\nexport const environmentToLensHubContract = (environment: Environment): string => {\n  switch (environment) {\n    case Environment.POLYGON:\n      return '0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d';\n    case Environment.MUMBAI:\n      return '0x60Ae865ee4C725cd04353b5AAb364553f56ceF82';\n    case Environment.AMOY:\n      return '0xA2574D9DdB6A325Ad2Be838Bd854228B80215148';\n    default:\n      throw new Error('Invalid environment');\n  }\n};\n"
  },
  {
    "path": "momoka-node/src/common/helpers.ts",
    "content": "/**\n * Creates a deep clone of the given object by converting it to a JSON string and then parsing it back to an object.\n * @param object - The object to clone.\n * @returns The cloned object.\n */\nexport const deepClone = <T>(object: T): T => {\n  return JSON.parse(JSON.stringify(object)) as T;\n};\n\n/**\n * Asynchronously sleeps for the given number of milliseconds.\n * @param milliseconds - The number of milliseconds to sleep.\n * @returns A Promise that resolves after the given number of milliseconds have elapsed.\n */\nexport const sleep = (milliseconds: number): Promise<void> => {\n  return new Promise((resolve) => setTimeout(resolve, milliseconds));\n};\n\n/**\n * Gets the value of the specified environment variable or exits the process if it is not defined.\n * @param name - The name of the environment variable to retrieve.\n * @returns The value of the specified environment variable.\n */\nexport const getParamOrExit = (name: string): string => {\n  const param = process.env[name];\n  if (!param) {\n    console.error(`Required config param '${name}' missing`);\n    process.exit(1);\n  }\n  return param;\n};\n\n/**\n * Gets the value of the specified environment variable or returns null if it is not defined.\n * @param name - The name of the environment variable to retrieve.\n * @returns The value of the specified environment variable or null if it is not defined.\n */\nexport const getParam = (name: string): string | null => {\n  const param = process.env[name];\n  if (!param) {\n    return null;\n  }\n  return param;\n};\n\n/**\n * Converts a base64-encoded string to a JSON object.\n * @param base64String - The base64-encoded string to convert.\n * @returns The resulting JSON object.\n */\nexport const base64StringToJson = <T>(base64String: string): T => {\n  const buffer = Buffer.from(base64String, 'base64');\n  const jsonString = buffer.toString('utf-8');\n  return JSON.parse(jsonString) as T;\n};\n\n/**\n * Converts a Unix timestamp to a JavaScript Date object represented in milliseconds.\n * @param unixTimestamp - The Unix timestamp to convert.\n * @returns The resulting timestamp in milliseconds.\n */\nexport const unixTimestampToMilliseconds = (unixTimestamp: number): number => unixTimestamp * 1000;\n\n/**\n * Pads a number to the left with zeroes.\n * @param nr - The number to pad.\n * @param len - The desired length of the resulting string (default: 2).\n * @param chr - The character to use for padding (default: '0').\n * @returns The resulting padded string.\n */\nconst padLeft = (nr: number, len = 2, chr = `0`): string => `${nr}`.padStart(len, chr);\n\n/**\n * Formats a JavaScript Date object as a human-readable string.\n * @param date - The Date object to format.\n * @returns The formatted date string.\n */\nexport const formatDate = (date: Date): string => {\n  return `${padLeft(date.getMonth() + 1)}/${padLeft(\n    date.getDate()\n  )}/${date.getFullYear()} ${padLeft(date.getHours())}:${padLeft(date.getMinutes())}:${padLeft(\n    date.getSeconds()\n  )}`;\n};\n\n/**\n *  Split arrays up into smaller chunks\n * @param arr The array to chunk\n * @param size The size of the chunks\n */\nexport const chunkArray = <T>(arr: T[], size: number): T[][] =>\n  arr.length > size ? [arr.slice(0, size), ...chunkArray(arr.slice(size), size)] : [arr];\n\n/**\n *  Create a promise that will timeout after the given number of milliseconds\n * @param timeout The number of milliseconds to wait before timing out\n */\nexport const createTimeoutPromise = (\n  timeout: number\n): {\n  promise: Promise<void>;\n  timeoutId: NodeJS.Timeout;\n} => {\n  const timeoutIdWrapper = { timeoutId: setTimeout(() => {}, 0) }; // Initialize with an empty function\n  clearTimeout(timeoutIdWrapper.timeoutId); // Clear the initial timeout\n\n  const promise = new Promise<void>((_, reject) => {\n    timeoutIdWrapper.timeoutId = setTimeout(() => reject(new Error('Timeout exceeded')), timeout);\n  });\n\n  return { promise, timeoutId: timeoutIdWrapper.timeoutId };\n};\n\ntype AsyncFunction<T> = () => Promise<T>;\n\nexport interface RetryWithTimeoutOptions {\n  delayMs?: number;\n  maxRetries?: number;\n}\n\n/**\n *  Retry a function with a timeout between retries\n * @param fn The function\n * @param options The options like delay and max retries\n */\nexport const retryWithTimeout = async <T>(\n  fn: AsyncFunction<T>,\n  options: RetryWithTimeoutOptions = {}\n): Promise<T> => {\n  let attempt = 0;\n\n  const maxRetries = options.maxRetries || 10;\n  const delayMs = options.delayMs || 100;\n  // eslint-disable-next-line no-constant-condition\n  while (true) {\n    try {\n      return await fn();\n    } catch (error) {\n      if (attempt <= maxRetries) {\n        await sleep(delayMs);\n        attempt++;\n      } else {\n        throw error;\n      }\n    }\n  }\n};\n\n/**\n * Simple abstraction to run a function forever\n * @param fn\n */\nexport const runForever = async (\n  fn: AsyncFunction<void>,\n  sleepAfterEach: number | undefined = undefined\n): Promise<never> => {\n  // eslint-disable-next-line no-constant-condition\n  while (true) {\n    await fn();\n    if (sleepAfterEach) {\n      await sleep(sleepAfterEach);\n    }\n  }\n};\n\n/**\n * node please stop saying fetch is experimental - we know and we are not even using it :)\n */\nexport const turnedOffExperimentalWarning = (): void => {\n  // node please stop saying fetch is experimental - we know and we are not even using it :)\n  const warningListeners = process.listeners('warning');\n  if (warningListeners.length != 1) {\n    console.warn(\n      `expected 1 listener on the process \"warning\" event, saw ${warningListeners.length}`\n    );\n  }\n\n  if (warningListeners[0]) {\n    const originalWarningListener = warningListeners[0];\n    process.removeAllListeners('warning');\n\n    process.prependListener('warning', (warning) => {\n      if (warning.name != 'ExperimentalWarning') {\n        originalWarningListener(warning);\n      }\n    });\n  }\n};\n"
  },
  {
    "path": "momoka-node/src/common/in-memory-store.ts",
    "content": "export class InMemoryStore {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  private state: Map<string, any>;\n\n  constructor() {\n    this.state = new Map<string, unknown>();\n  }\n\n  public set<T>(key: string, value: T): void {\n    this.state.set(key, value);\n  }\n\n  public get<TResponse>(key: string): TResponse | undefined {\n    return this.state.get(key);\n  }\n\n  public has(key: string): boolean {\n    return this.state.has(key);\n  }\n\n  public delete(key: string): boolean {\n    return this.state.delete(key);\n  }\n\n  public clear(): void {\n    this.state.clear();\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/common/logger.ts",
    "content": "export type LogFunctionType = (message: string, ...optionalParams: unknown[]) => void;\n\nexport enum LoggerLevelColours {\n  INFO = '\\x1b[36m',\n  SUCCESS = '\\x1b[38;2;0;128;0m',\n  ERROR = '\\x1b[31m',\n  WARNING = '\\x1b[33m',\n}\n\n/**\n *  A function to build a log message with the lens node footprint.\n * @param message The message\n */\nexport const buildLensNodeFootprintLog = (message: string): string => {\n  return `[${new Date().toUTCString()}] LENS VERIFICATION NODE - ${message}`;\n};\n\n/**\n * A function to log a message to the console with a info font color.\n * @param message - The message to be logged to the console.\n * @param optionalParams - An optional list of additional parameters to be logged to the console.\n */\nexport const consoleLog = (message: string, ...optionalParams: unknown[]): void => {\n  console.log(\n    LoggerLevelColours.INFO,\n    `[${new Date().toUTCString()}] ${message}`,\n    ...optionalParams\n  );\n};\n\n/**\n * A function to log a message to the console with a info font color including the lens node footprint.\n * @param message - The message to be logged to the console.\n * @param optionalParams - An optional list of additional parameters to be logged to the console.\n */\nexport const consoleLogWithLensNodeFootprint = (\n  message: string,\n  ...optionalParams: unknown[]\n): void => {\n  console.log(LoggerLevelColours.INFO, buildLensNodeFootprintLog(message), ...optionalParams);\n};\n\n/**\n * A function to log a message to the console with a green font color.\n * @param message - The message to be logged to the console.\n * @param optionalParams - An optional list of additional parameters to be logged to the console.\n */\nexport const consoleSuccess = (message: string, ...optionalParams: unknown[]): void => {\n  console.log(\n    LoggerLevelColours.SUCCESS,\n    `[${new Date().toUTCString()}] ${message}`,\n    ...optionalParams\n  );\n};\n\n/**\n * A function to log a error message to the console with a red font color.\n * @param message - The message to be logged to the console.\n * @param optionalParams - An optional list of additional parameters to be logged to the console.\n */\nexport const consoleError = (message: string, ...optionalParams: unknown[]): void => {\n  console.log(\n    LoggerLevelColours.ERROR,\n    `[${new Date().toUTCString()}] ${message}`,\n    ...optionalParams\n  );\n};\n\n/**\n * A function to log a warning message to the console with a yellow font color.\n * @param message - The message to be logged to the console.\n * @param optionalParams - An optional list of additional parameters to be logged to the console.\n */\nexport const consoleWarn = (message: string, ...optionalParams: unknown[]): void => {\n  console.log(\n    LoggerLevelColours.WARNING,\n    `[${new Date().toUTCString()}] ${message}`,\n    ...optionalParams\n  );\n};\n\n/**\n * A function to log a message to the console with a dyanmic font color.\n * @param message - The message to be logged to the console.\n * @param optionalParams - An optional list of additional parameters to be logged to the console.\n */\nexport const consoleDynamic = (\n  color: LoggerLevelColours,\n  message: string,\n  ...optionalParams: unknown[]\n): void => {\n  console.log(color, `[${new Date().toUTCString()}] ${message}`, ...optionalParams);\n};\n"
  },
  {
    "path": "momoka-node/src/data-availability-models/da-result.ts",
    "content": "import { MomokaValidatorError } from './validator-errors';\n\nclass Success<TSuccess> {\n  public constructor(public readonly successResult: TSuccess) {}\n\n  public isSuccess(): this is Success<TSuccess> {\n    return true;\n  }\n\n  public isFailure(): this is Failure<never, never> {\n    return false;\n  }\n}\n\nclass Failure<TError, TContext = undefined> {\n  public constructor(public readonly failure: TError, public context?: TContext) {}\n\n  public isSuccess(): this is Success<never> {\n    return false;\n  }\n\n  public isFailure(): this is Failure<TError, TContext> {\n    return true;\n  }\n}\n\n/**\n * Represents the result of a data availability check.\n * @template TSuccessResult The type of the successful result.\n * @template TContext The type of the context, which is undefined by default.\n */\nexport type DAResult<TSuccessResult, TContext = undefined> =\n  | Success<TSuccessResult>\n  | Failure<MomokaValidatorError, TContext>;\n\n/**\n * Represents a Promise of a data availability result.\n * @template TSuccessResult The type of the successful result.\n */\nexport type PromiseResult<TSuccessResult = void> = Promise<DAResult<TSuccessResult>>;\n\n/**\n * Represents a data availability result.\n * @template TSuccessResult The type of the successful result.\n */\nexport type Result<TSuccessResult = void> = DAResult<TSuccessResult>;\n\n/**\n * Creates a successful data availability result.\n * @template TResult The type of the successful result.\n * @param result The successful result.\n * @returns The successful data availability result.\n */\nexport function success(): Success<void>;\nexport function success<T>(result: T): Success<T>;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any, prefer-arrow/prefer-arrow-functions\nexport function success<T>(result: any = undefined): Success<T> {\n  return new Success(result);\n}\n\n/**\n * Creates a failed data availability result.\n * @param error The claimable validator error in case of failure.\n * @returns The failed data availability result.\n */\nexport const failure = (error: MomokaValidatorError): Failure<MomokaValidatorError> =>\n  new Failure(error);\n\n/**\n * Represents a Promise of a data availability result with context.\n * @template TSuccessResult The type of the successful result.\n * @template TContext The type of the context.\n */\nexport type PromiseWithContextResult<TSuccessResult, TContext> = Promise<\n  DAResult<TSuccessResult, TContext>\n>;\n\n/**\n * Represents a Promise of a data availability result with optional context.\n * @template TSuccessResult The type of the successful result.\n * @template TContext The type of the context.\n */\nexport type PromiseWithContextResultOrNull<TSuccessResult, TContext> = Promise<DAResult<\n  TSuccessResult,\n  TContext\n> | null>;\n\n/**\n * Creates a failed data availability result with context.\n * @template TContext The type of the context.\n * @param error The claimable validator error in case of failure.\n * @param context The context associated with the result.\n * @returns The failed data availability result with context.\n */\nexport const failureWithContext = <TContext>(\n  error: MomokaValidatorError,\n  context: TContext\n): Failure<MomokaValidatorError, TContext> => new Failure(error, context);\n"
  },
  {
    "path": "momoka-node/src/data-availability-models/data-availability-action-types.ts",
    "content": "export enum MomokaActionTypes {\n  POST_CREATED = 'POST_CREATED',\n  COMMENT_CREATED = 'COMMENT_CREATED',\n  MIRROR_CREATED = 'MIRROR_CREATED',\n  QUOTE_CREATED = 'QUOTE_CREATED',\n}\n"
  },
  {
    "path": "momoka-node/src/data-availability-models/data-availability-provider.ts",
    "content": "export enum MomokaProvider {\n  BUNDLR = 'BUNDLR',\n}\n"
  },
  {
    "path": "momoka-node/src/data-availability-models/data-availability-structure-base.ts",
    "content": "import { MomokaActionTypes } from './data-availability-action-types';\nimport { DATimestampProofs } from './data-availability-timestamp-proofs';\n\nexport interface DAStructureBase {\n  /**\n   * The ID which links all the other proofs together\n   */\n  dataAvailabilityId: string;\n\n  /**\n   * The signature of the entire payload by the submitter\n   */\n  signature: string;\n\n  /**\n   * The DA action type\n   */\n  type: MomokaActionTypes;\n\n  /**\n   * The timestamp proofs\n   */\n  timestampProofs: DATimestampProofs;\n}\n"
  },
  {
    "path": "momoka-node/src/data-availability-models/data-availability-timestamp-proofs.ts",
    "content": "import { MomokaActionTypes } from './data-availability-action-types';\nimport { MomokaProvider } from './data-availability-provider';\nimport { DAPublicationsBatchResult } from './publications/data-availability-structure-publication';\n\nexport type DATimestampProofs = BundlrTimestampProofs;\n\nexport interface BundlrUploadResponse {\n  // The ID of the transaction\n  id: string;\n  // The Arweave public key of the node that received the transaction\n  public: string;\n  // The signature of this receipt\n  signature: string;\n  // response version\n  version: '1.0.0';\n  // the maximum expected Arweave block height for transaction inclusion\n  block: number;\n  deadlineHeight: number;\n  // List of validator signatures\n  validatorSignatures: { address: string; signature: string }[];\n  // The UNIX (MS precision) timestamp of when the node received the Tx. Only optional if the upload receives a `201` error in response to a duplicate transaction upload.\n  timestamp: number;\n}\n\nexport interface BundlrTimestampProofs {\n  /**\n   * The proofs type\n   */\n  type: MomokaProvider.BUNDLR;\n\n  /**\n   * The hash prefix may not change for 10 years but good to know!\n   */\n  hashPrefix: '1';\n  /**\n   * The response from bundlr including the timestamp\n   */\n  response: BundlrUploadResponse;\n}\n\nexport interface DATimestampProofsResponse {\n  type: MomokaActionTypes;\n  dataAvailabilityId: string;\n}\n\nexport interface DAPublicationWithTimestampProofsBatchResult extends DAPublicationsBatchResult {\n  timestampProofsData: DATimestampProofsResponse;\n}\n"
  },
  {
    "path": "momoka-node/src/data-availability-models/data-availability-typed-data.ts",
    "content": "export interface TypedDataField {\n  name: string;\n  type: string;\n}\n\nexport interface TypedDataDomain {\n  name: string;\n  version: string;\n  chainId: number;\n  verifyingContract: string;\n}\n\nexport interface EIP712TypedDataValueBase {\n  nonce: number;\n  deadline: number;\n}\n"
  },
  {
    "path": "momoka-node/src/data-availability-models/publications/data-availability-publication-typed-data.ts",
    "content": "import {\n  EIP712TypedDataValueBase,\n  TypedDataDomain,\n  TypedDataField,\n} from '../data-availability-typed-data';\n\ninterface CreatePostV1EIP712TypedDataValue extends EIP712TypedDataValueBase {\n  profileId: string;\n  contentURI: string;\n  collectModule: string;\n  collectModuleInitData: string;\n  referenceModule: string;\n  referenceModuleInitData: string;\n}\n\ninterface CreatePostV2EIP712TypedDataValue extends EIP712TypedDataValueBase {\n  profileId: string;\n  contentURI: string;\n  actionModules: string[];\n  actionModulesInitDatas: string[];\n  referenceModule: string;\n  referenceModuleInitData: string;\n}\n\nexport interface CreatePostV1EIP712TypedData {\n  types: {\n    PostWithSig: Array<TypedDataField>;\n  };\n  domain: TypedDataDomain;\n  value: CreatePostV1EIP712TypedDataValue;\n}\n\nexport interface CreatePostV2EIP712TypedData {\n  types: {\n    PostWithSig: Array<TypedDataField>;\n  };\n  domain: TypedDataDomain;\n  value: CreatePostV2EIP712TypedDataValue;\n}\n\ninterface CreateCommentV1EIP712TypedDataValue extends EIP712TypedDataValueBase {\n  profileId: string;\n  contentURI: string;\n  profileIdPointed: string;\n  pubIdPointed: string;\n  referenceModule: string;\n  collectModule: string;\n  collectModuleInitData: string;\n  referenceModuleInitData: string;\n  referenceModuleData: string;\n}\n\ninterface CreateCommentV2EIP712TypedDataValue extends EIP712TypedDataValueBase {\n  profileId: string;\n  contentURI: string;\n  pointedProfileId: string;\n  pointedPubId: string;\n  referrerProfileIds: string[];\n  referrerPubIds: string[];\n  referenceModuleData: string;\n  actionModules: string[];\n  actionModulesInitDatas: string[];\n  referenceModule: string;\n  referenceModuleInitData: string;\n}\n\nexport interface CreateCommentV1EIP712TypedData {\n  types: {\n    CommentWithSig: Array<TypedDataField>;\n  };\n  domain: TypedDataDomain;\n  value: CreateCommentV1EIP712TypedDataValue;\n}\n\nexport interface CreateCommentV2EIP712TypedData {\n  types: {\n    CommentWithSig: Array<TypedDataField>;\n  };\n  domain: TypedDataDomain;\n  value: CreateCommentV2EIP712TypedDataValue;\n}\n\nexport interface CreateMirrorV1EIP712TypedDataValue extends EIP712TypedDataValueBase {\n  profileId: string;\n  profileIdPointed: string;\n  pubIdPointed: string;\n  referenceModuleData: string;\n  referenceModule: string;\n  referenceModuleInitData: string;\n}\n\nexport interface CreateMirrorV2EIP712TypedDataValue extends EIP712TypedDataValueBase {\n  profileId: string;\n  pointedProfileId: string;\n  pointedPubId: string;\n  referenceModuleData: string;\n  metadataURI: string;\n  referrerPubIds: string[];\n  referrerProfileIds: string[];\n}\n\nexport interface CreateMirrorV1EIP712TypedData {\n  types: {\n    MirrorWithSig: Array<TypedDataField>;\n  };\n  domain: TypedDataDomain;\n  value: CreateMirrorV1EIP712TypedDataValue;\n}\n\nexport interface CreateMirrorV2EIP712TypedData {\n  types: {\n    MirrorWithSig: Array<TypedDataField>;\n  };\n  domain: TypedDataDomain;\n  value: CreateMirrorV2EIP712TypedDataValue;\n}\n\ninterface CreatQuoteV2EIP712TypedDataValue extends EIP712TypedDataValueBase {\n  profileId: string;\n  contentURI: string;\n  pointedProfileId: string;\n  pointedPubId: string;\n  referrerProfileIds: string[];\n  referrerPubIds: string[];\n  referenceModuleData: string;\n  actionModules: string[];\n  actionModulesInitDatas: string[];\n  referenceModule: string;\n  referenceModuleInitData: string;\n}\n\nexport interface CreateQuoteV2EIP712TypedData {\n  types: {\n    MirrorWithSig: Array<TypedDataField>;\n  };\n  domain: TypedDataDomain;\n  value: CreatQuoteV2EIP712TypedDataValue;\n}\n\nexport type PublicationV1TypedData =\n  | CreatePostV1EIP712TypedData\n  | CreateCommentV1EIP712TypedData\n  | CreateMirrorV1EIP712TypedData;\n\nexport type PublicationV2TypedData =\n  | CreatePostV2EIP712TypedData\n  | CreateCommentV2EIP712TypedData\n  | CreateMirrorV2EIP712TypedData\n  | CreateQuoteV2EIP712TypedData;\n\nexport type PublicationTypedData = PublicationV1TypedData | PublicationV2TypedData;\n"
  },
  {
    "path": "momoka-node/src/data-availability-models/publications/data-availability-structure-publication.ts",
    "content": "import { DAStructureBase } from '../data-availability-structure-base';\nimport { DAEventType } from './data-availability-structure-publications-events';\nimport { PublicationTypedData } from './data-availability-publication-typed-data';\n\nexport enum DAPublicationPointerType {\n  ON_EVM_CHAIN = 'ON_EVM_CHAIN',\n  ON_DA = 'ON_DA',\n}\n\ninterface DAStructurePublicationProofs<TTypedData extends PublicationTypedData> {\n  thisPublication: {\n    /**\n     * The signature which can be submitted on that block to prove the publication would of passed\n     */\n    signature: string;\n\n    /**\n     * The signature has been signed by a delegate/dispatcher\n     */\n    signedByDelegate: boolean;\n\n    /**\n     * The signature deadline unix timestamp\n     */\n    signatureDeadline: number;\n\n    /**\n     * The typed data that was signed\n     */\n    typedData: TTypedData;\n\n    /**\n     * The block hash of the block that contains the proof and should be ran on\n     */\n    blockHash: string;\n\n    /**\n     * The block timestamp the proof ran on\n     */\n    blockTimestamp: number;\n\n    /**\n     * The block number at this point make sure hash matches (you fork on block number not on block hash)\n     */\n    blockNumber: number;\n  };\n\n  /**\n   * This is the pointers proofs, if the publication is another DA publication then this will be the proofs of that publication\n   */\n  pointer: {\n    /**\n     * The location of the pointer\n     */\n    location: string;\n    /**\n     * This maps if the pointer type is a DA publication or on the evm chain\n     */\n    type: DAPublicationPointerType;\n  } | null;\n}\n\n// TODO: Refactor to discriminated union by `type` so narrowing works properly\nexport interface DAStructurePublication<\n  TEvent extends DAEventType = DAEventType,\n  TTypedData extends PublicationTypedData = PublicationTypedData\n> extends DAStructureBase {\n  /**\n   * As close if not exactly the same as how the blockchain event was emitted.\n   */\n  event: TEvent;\n\n  /**\n   * The proofs that can be verified on the blockchain.\n   */\n  chainProofs: DAStructurePublicationProofs<TTypedData>;\n\n  /**\n   * The unquie publication id should be used as the primary key in the database\n   * and should be a build up of data availability id and the publication id\n   */\n  publicationId: string;\n}\n\nexport interface DAPublicationsBatchResult {\n  id: string;\n  daPublication: DAStructurePublication;\n  submitter: string;\n}\n\n// TODO: This is done to avoid modifying a lot of files. Remove this when we have time as DAStructurePublication has these as default.\nexport { DAEventType, PublicationTypedData };\n"
  },
  {
    "path": "momoka-node/src/data-availability-models/publications/data-availability-structure-publications-events.ts",
    "content": "import {\n  PostCreatedEventEmittedResponse as PostCreatedEventEmittedResponseV1,\n  MirrorCreatedEventEmittedResponse as MirrorCreatedEventEmittedResponseV1,\n  CommentCreatedEventEmittedResponse as CommentCreatedEventEmittedResponseV1,\n} from '../../evm/abi-types/LensHubV1Events';\n\nimport {\n  PostCreatedEventEmittedResponse as PostCreatedEventEmittedResponseV2,\n  CommentCreatedEventEmittedResponse as CommentCreatedEventEmittedResponseV2,\n  MirrorCreatedEventEmittedResponse as MirrorCreatedEventEmittedResponseV2,\n  QuoteCreatedEventEmittedResponse as QuoteCreatedEventEmittedResponseV2,\n} from '../../evm/abi-types/LensHubV2Events';\n\nexport type DAPostCreatedEventEmittedResponseV1 = PostCreatedEventEmittedResponseV1;\nexport type DAPostCreatedEventEmittedResponseV2 = PostCreatedEventEmittedResponseV2;\nexport type DAPostCreatedEventEmittedResponse =\n  | DAPostCreatedEventEmittedResponseV1\n  | DAPostCreatedEventEmittedResponseV2;\n\nexport type DACommentCreatedEventEmittedResponseV1 = CommentCreatedEventEmittedResponseV1;\nexport type DACommentCreatedEventEmittedResponseV2 = CommentCreatedEventEmittedResponseV2;\nexport type DACommentCreatedEventEmittedResponse =\n  | DACommentCreatedEventEmittedResponseV1\n  | DACommentCreatedEventEmittedResponseV2;\n\nexport type DAMirrorCreatedEventEmittedResponseV1 = MirrorCreatedEventEmittedResponseV1;\nexport type DAMirrorCreatedEventEmittedResponseV2 = MirrorCreatedEventEmittedResponseV2;\nexport type DAMirrorCreatedEventEmittedResponse =\n  | DAMirrorCreatedEventEmittedResponseV1\n  | DAMirrorCreatedEventEmittedResponseV2;\n\nexport type DAQuoteCreatedEventEmittedResponseV2 = QuoteCreatedEventEmittedResponseV2;\nexport type DAQuoteCreatedEventEmittedResponse = DAQuoteCreatedEventEmittedResponseV2;\n\nexport type DAEventTypeV1 =\n  | DAPostCreatedEventEmittedResponseV1\n  | DACommentCreatedEventEmittedResponseV1\n  | DAMirrorCreatedEventEmittedResponseV1;\n\nexport type DAEventTypeV2 =\n  | DAPostCreatedEventEmittedResponseV2\n  | DACommentCreatedEventEmittedResponseV2\n  | DAMirrorCreatedEventEmittedResponseV2\n  | DAQuoteCreatedEventEmittedResponseV2;\n\nexport type DAEventType = DAEventTypeV1 | DAEventTypeV2;\n"
  },
  {
    "path": "momoka-node/src/data-availability-models/validator-errors.ts",
    "content": "/**\n * This is a list of all the errors that can be returned from the momoka validator\n */\nexport enum MomokaValidatorError {\n  /**\n   * This means the main signature has not been attached to the payload\n   */\n  NO_SIGNATURE_SUBMITTER = 'NO_SIGNATURE_SUBMITTER',\n\n  /**\n   * This means the main signature has not been signed by the same payload as the data itself\n   */\n  INVALID_SIGNATURE_SUBMITTER = 'INVALID_SIGNATURE_SUBMITTER',\n\n  /**\n   * This means the submitted timestamp proof does not have a valid timestamp proof signature\n   */\n  TIMESTAMP_PROOF_INVALID_SIGNATURE = 'TIMESTAMP_PROOF_INVALID_SIGNATURE',\n\n  /**\n   * This means the type in the timestamp proofs do not match\n   * timestamp proofs are not portable\n   */\n  TIMESTAMP_PROOF_INVALID_TYPE = 'TIMESTAMP_PROOF_INVALID_TYPE',\n\n  /**\n   * This means the da id in the timestamp proofs do not match up\n   * timestamp proofs are not portable\n   */\n  TIMESTAMP_PROOF_INVALID_DA_ID = 'TIMESTAMP_PROOF_INVALID_DA_ID',\n\n  /**\n   * This means the timestamp proof uploaded was not done by a valid submitter\n   */\n  TIMESTAMP_PROOF_NOT_SUBMITTER = 'TIMESTAMP_PROOF_NOT_SUBMITTER',\n\n  /**\n   * We tried to call them 5 times and its errored out - this is not a bad proof but bundlr/arweave are having issues\n   */\n  CAN_NOT_CONNECT_TO_BUNDLR = 'CAN_NOT_CONNECT_TO_BUNDLR',\n\n  /**\n   * The DA tx could not be found or invalid on the bundlr/arweave nodes\n   * can happened if pasted it in wrong\n   */\n  INVALID_TX_ID = 'INVALID_TX_ID',\n\n  /**\n   * This the typed data format is invalid (aka a invalid address type etc)\n   */\n  INVALID_FORMATTED_TYPED_DATA = 'INVALID_FORMATTED_TYPED_DATA',\n\n  /**\n   * This means it can not read the block from the node\n   */\n  BLOCK_CANT_BE_READ_FROM_NODE = 'BLOCK_CANT_BE_READ_FROM_NODE',\n\n  /**\n   * This means it can not read the data from the node\n   */\n  DATA_CANT_BE_READ_FROM_NODE = 'DATA_CANT_BE_READ_FROM_NODE',\n\n  /**\n   * This means the simulation was not able to be ran on the node, this does not mean\n   * that it would fail on chain, it means the nodes may of been down and needs rechecking\n   */\n  SIMULATION_NODE_COULD_NOT_RUN = 'SIMULATION_NODE_COULD_NOT_RUN',\n\n  /**\n   * This means the simulation was not successful and got rejected on-chain\n   * or the result from the simulation did not match the expected result\n   */\n  SIMULATION_FAILED = 'SIMULATION_FAILED',\n\n  /**\n   * This means the event emitted from the simulation does not match the expected event\n   */\n  EVENT_MISMATCH = 'EVENT_MISMATCH',\n\n  /**\n   * This means the event timestamp passed into the emitted event does not match the signature timestamp\n   */\n  INVALID_EVENT_TIMESTAMP = 'INVALID_EVENT_TIMESTAMP',\n\n  /**\n   * This means the deadline set in the typed data is not correct\n   */\n  INVALID_TYPED_DATA_DEADLINE_TIMESTAMP = 'INVALID_TYPED_DATA_DEADLINE_TIMESTAMP',\n\n  /**\n   * This means the generated publication id for the generic id does not match\n   * what it should be\n   */\n  GENERATED_PUBLICATION_ID_MISMATCH = 'GENERATED_PUBLICATION_ID_MISMATCH',\n\n  /**\n   * This means the pointer set in the chain proofs is not required but set anyway\n   */\n  INVALID_POINTER_SET_NOT_NEEDED = 'INVALID_POINTER_SET_NOT_NEEDED',\n\n  /**\n   * This means the pointer has failed verification\n   */\n  POINTER_FAILED_VERIFICATION = 'POINTER_FAILED_VERIFICATION',\n\n  /**\n   * This means the block processed against is not the closest block to the timestamp proofs\n   */\n  NOT_CLOSEST_BLOCK = 'NOT_CLOSEST_BLOCK',\n\n  /**\n   * This means the timestamp proofs are not close enough to the block\n   */\n  BLOCK_TOO_FAR = 'NOT_CLOSEST_BLOCK',\n\n  /**\n   * This means the publication submitted does not have a valid pointer\n   * and a pointer is required\n   */\n  PUBLICATION_NO_POINTER = 'PUBLICATION_NO_POINTER',\n\n  /**\n   * Some publications (comment and mirror) for now can only be on another\n   * DA publication not on evm chain publications\n   */\n  PUBLICATION_NONE_DA = 'PUBLICATION_NONE_DA',\n\n  /**\n   * This means the publication nonce is invalid at the time of submission\n   */\n  PUBLICATION_NONCE_INVALID = 'PUBLICATION_NONCE_INVALID',\n\n  /**\n   * This means the publication submisson was signed by a wallet that is not allowed\n   */\n  PUBLICATION_SIGNER_NOT_ALLOWED = 'PUBLICATION_SIGNER_NOT_ALLOWED',\n\n  /**\n   * This means the evm signature has already been used\n   * Only really starts to be able to be properly used when many submitters\n   */\n  CHAIN_SIGNATURE_ALREADY_USED = 'CHAIN_SIGNATURE_ALREADY_USED',\n\n  /**\n   * This means the publication submisson could not pass potentional due to a reorg\n   */\n  POTENTIAL_REORG = 'POTENTIAL_REORG',\n\n  /**\n   * This means there was a new version of the metadata that was not able to be processed.\n   * Update the library to the latest version.\n   */\n  PUBLICATION_NOT_RECOGNIZED = 'PUBLICATION_NOT_RECOGNIZED',\n\n  /**\n   * Unknown error should not happen but catch all\n   */\n  UNKNOWN = 'UNKNOWN',\n}\n"
  },
  {
    "path": "momoka-node/src/evm/abi-types/LensHubV1.ts",
    "content": "import { EthersContractContextV5 } from 'ethereum-abi-types-generator';\nimport { BigNumber, BigNumberish, BytesLike as Arrayish, ContractTransaction } from 'ethers';\n\nexport type ContractContext = EthersContractContextV5<\n  LensHubV1,\n  LensHubMethodNames,\n  LensHubEventsContext,\n  LensHubEvents\n>;\n\nexport declare type EventFilter = {\n  address?: string;\n  topics?: Array<string>;\n  fromBlock?: string | number;\n  toBlock?: string | number;\n};\n\nexport interface ContractTransactionOverrides {\n  /**\n   * The maximum units of gas for the transaction to use\n   */\n  gasLimit?: number;\n  /**\n   * The price (in wei) per unit of gas\n   */\n  gasPrice?: BigNumber | string | number | Promise<any>;\n  /**\n   * The nonce to use in the transaction\n   */\n  nonce?: number;\n  /**\n   * The amount to send with the transaction (i.e. msg.value)\n   */\n  value?: BigNumber | string | number | Promise<any>;\n  /**\n   * The chain ID (or network ID) to use\n   */\n  chainId?: number;\n}\n\nexport interface ContractCallOverrides {\n  /**\n   * The address to execute the call as\n   */\n  from?: string;\n  /**\n   * The maximum units of gas for the transaction to use\n   */\n  gasLimit?: number;\n\n  /**\n   * The block tag!\n   */\n  blockTag?: string | number;\n}\nexport type LensHubEvents = 'Approval' | 'ApprovalForAll' | 'Transfer';\nexport interface LensHubEventsContext {\n  Approval(...parameters: any): EventFilter;\n  ApprovalForAll(...parameters: any): EventFilter;\n  Transfer(...parameters: any): EventFilter;\n}\nexport type LensHubMethodNames =\n  | 'new'\n  | 'approve'\n  | 'balanceOf'\n  | 'burn'\n  | 'burnWithSig'\n  | 'collect'\n  | 'collectWithSig'\n  | 'comment'\n  | 'commentWithSig'\n  | 'commentWithSig_Dispatcher'\n  | 'createProfile'\n  | 'defaultProfile'\n  | 'emitCollectNFTTransferEvent'\n  | 'emitFollowNFTTransferEvent'\n  | 'exists'\n  | 'follow'\n  | 'followWithSig'\n  | 'getApproved'\n  | 'getCollectModule'\n  | 'getCollectNFT'\n  | 'getCollectNFTImpl'\n  | 'getContentURI'\n  | 'getDispatcher'\n  | 'getDomainSeparator'\n  | 'getFollowModule'\n  | 'getFollowNFT'\n  | 'getFollowNFTImpl'\n  | 'getFollowNFTURI'\n  | 'getGovernance'\n  | 'getHandle'\n  | 'getProfile'\n  | 'getProfileIdByHandle'\n  | 'getPub'\n  | 'getPubCount'\n  | 'getPubPointer'\n  | 'getPubType'\n  | 'getReferenceModule'\n  | 'getState'\n  | 'initialize'\n  | 'isApprovedForAll'\n  | 'isCollectModuleWhitelisted'\n  | 'isFollowModuleWhitelisted'\n  | 'isProfileCreatorWhitelisted'\n  | 'isReferenceModuleWhitelisted'\n  | 'mintTimestampOf'\n  | 'mirror'\n  | 'mirrorWithSig'\n  | 'mirrorWithSig_Dispatcher'\n  | 'name'\n  | 'ownerOf'\n  | 'permit'\n  | 'permitForAll'\n  | 'post'\n  | 'postWithSig'\n  | 'postWithSig_Dispatcher'\n  | 'safeTransferFrom'\n  | 'setApprovalForAll'\n  | 'setDefaultProfile'\n  | 'setDefaultProfileWithSig'\n  | 'setDispatcher'\n  | 'setDispatcherWithSig'\n  | 'setEmergencyAdmin'\n  | 'setFollowModule'\n  | 'setFollowModuleWithSig'\n  | 'setFollowNFTURI'\n  | 'setFollowNFTURIWithSig'\n  | 'setGovernance'\n  | 'setProfileImageURI'\n  | 'setProfileImageURIWithSig'\n  | 'setState'\n  | 'sigNonces'\n  | 'supportsInterface'\n  | 'symbol'\n  | 'tokenByIndex'\n  | 'tokenDataOf'\n  | 'tokenOfOwnerByIndex'\n  | 'tokenURI'\n  | 'totalSupply'\n  | 'transferFrom'\n  | 'whitelistCollectModule'\n  | 'whitelistFollowModule'\n  | 'whitelistProfileCreator'\n  | 'whitelistReferenceModule';\nexport interface ApprovalEventEmittedResponse {\n  owner: string;\n  approved: string;\n  tokenId: BigNumberish;\n}\nexport interface ApprovalForAllEventEmittedResponse {\n  owner: string;\n  operator: string;\n  approved: boolean;\n}\nexport interface TransferEventEmittedResponse {\n  from: string;\n  to: string;\n  tokenId: BigNumberish;\n}\nexport interface BurnWithSigRequest {\n  v: BigNumberish;\n  r: Arrayish;\n  s: Arrayish;\n  deadline: BigNumberish;\n}\nexport interface SigRequest {\n  v: BigNumberish;\n  r: Arrayish;\n  s: Arrayish;\n  deadline: BigNumberish;\n}\nexport interface CollectWithSigRequest {\n  collector: string;\n  profileId: BigNumberish;\n  pubId: BigNumberish;\n  data: Arrayish;\n  sig: SigRequest;\n}\nexport interface CommentRequest {\n  profileId: BigNumberish;\n  contentURI: string;\n  profileIdPointed: BigNumberish;\n  pubIdPointed: BigNumberish;\n  referenceModuleData: Arrayish;\n  collectModule: string;\n  collectModuleInitData: Arrayish;\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n}\nexport interface CommentWithSigRequest {\n  profileId: BigNumberish;\n  contentURI: string;\n  profileIdPointed: BigNumberish;\n  pubIdPointed: BigNumberish;\n  referenceModuleData: Arrayish;\n  collectModule: string;\n  collectModuleInitData: Arrayish;\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n  sig: SigRequest;\n}\nexport interface CommentWithSig_DispatcherRequest {\n  profileId: BigNumberish;\n  contentURI: string;\n  profileIdPointed: BigNumberish;\n  pubIdPointed: BigNumberish;\n  referenceModuleData: Arrayish;\n  collectModule: string;\n  collectModuleInitData: Arrayish;\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n  sig: SigRequest;\n}\nexport interface CreateProfileRequest {\n  to: string;\n  handle: string;\n  imageURI: string;\n  followModule: string;\n  followModuleInitData: Arrayish;\n  followNFTURI: string;\n}\nexport interface FollowWithSigRequest {\n  follower: string;\n  profileIds: BigNumberish[];\n  datas: Arrayish[];\n  sig: SigRequest;\n}\nexport interface ProfileResponse {\n  pubCount: BigNumber;\n  0: BigNumber;\n  followModule: string;\n  1: string;\n  followNFT: string;\n  2: string;\n  handle: string;\n  3: string;\n  imageURI: string;\n  4: string;\n  followNFTURI: string;\n  5: string;\n}\nexport interface PublicationResponse {\n  profileIdPointed: BigNumber;\n  0: BigNumber;\n  pubIdPointed: BigNumber;\n  1: BigNumber;\n  contentURI: string;\n  2: string;\n  referenceModule: string;\n  3: string;\n  collectModule: string;\n  4: string;\n  collectNFT: string;\n  5: string;\n}\nexport interface GetPubPointerResponse {\n  result0: BigNumber;\n  0: BigNumber;\n  result1: BigNumber;\n  1: BigNumber;\n  length: 2;\n}\nexport interface MirrorRequest {\n  profileId: BigNumberish;\n  profileIdPointed: BigNumberish;\n  pubIdPointed: BigNumberish;\n  referenceModuleData: Arrayish;\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n}\nexport interface MirrorWithSigRequest {\n  profileId: BigNumberish;\n  profileIdPointed: BigNumberish;\n  pubIdPointed: BigNumberish;\n  referenceModuleData: Arrayish;\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n  sig: SigRequest;\n}\nexport interface MirrorWithSig_DispatcherRequest {\n  profileId: BigNumberish;\n  profileIdPointed: BigNumberish;\n  pubIdPointed: BigNumberish;\n  referenceModuleData: Arrayish;\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n  sig: SigRequest;\n}\nexport interface PermitRequest {\n  v: BigNumberish;\n  r: Arrayish;\n  s: Arrayish;\n  deadline: BigNumberish;\n}\nexport interface PermitForAllRequest {\n  v: BigNumberish;\n  r: Arrayish;\n  s: Arrayish;\n  deadline: BigNumberish;\n}\nexport interface PostRequest {\n  profileId: BigNumberish;\n  contentURI: string;\n  collectModule: string;\n  collectModuleInitData: Arrayish;\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n}\nexport interface PostWithSigRequest {\n  profileId: BigNumberish;\n  contentURI: string;\n  collectModule: string;\n  collectModuleInitData: Arrayish;\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n  sig: SigRequest;\n}\nexport interface PostWithSig_DispatcherRequest {\n  profileId: BigNumberish;\n  contentURI: string;\n  collectModule: string;\n  collectModuleInitData: Arrayish;\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n  sig: SigRequest;\n}\nexport interface SetDefaultProfileWithSigRequest {\n  wallet: string;\n  profileId: BigNumberish;\n  sig: SigRequest;\n}\nexport interface SetDispatcherWithSigRequest {\n  profileId: BigNumberish;\n  dispatcher: string;\n  sig: SigRequest;\n}\nexport interface SetFollowModuleWithSigRequest {\n  profileId: BigNumberish;\n  followModule: string;\n  followModuleInitData: Arrayish;\n  sig: SigRequest;\n}\nexport interface SetFollowNFTURIWithSigRequest {\n  profileId: BigNumberish;\n  followNFTURI: string;\n  sig: SigRequest;\n}\nexport interface SetProfileImageURIWithSigRequest {\n  profileId: BigNumberish;\n  imageURI: string;\n  sig: SigRequest;\n}\nexport interface TokendataResponse {\n  owner: string;\n  0: string;\n  mintTimestamp: BigNumber;\n  1: BigNumber;\n}\nexport interface LensHubV1 {\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: constructor\n   * @param followNFTImpl Type: address, Indexed: false\n   * @param collectNFTImpl Type: address, Indexed: false\n   */\n  'new'(\n    followNFTImpl: string,\n    collectNFTImpl: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param to Type: address, Indexed: false\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  approve(\n    to: string,\n    tokenId: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param owner Type: address, Indexed: false\n   */\n  balanceOf(owner: string, overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  burn(\n    tokenId: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   * @param sig Type: tuple, Indexed: false\n   */\n  burnWithSig(\n    tokenId: BigNumberish,\n    sig: BurnWithSigRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   * @param data Type: bytes, Indexed: false\n   */\n  collect(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    data: Arrayish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  collectWithSig(\n    vars: CollectWithSigRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  comment(\n    vars: CommentRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  commentWithSig(\n    vars: CommentWithSigRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  commentWithSig_Dispatcher(\n    vars: CommentWithSig_DispatcherRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  createProfile(\n    vars: CreateProfileRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param wallet Type: address, Indexed: false\n   */\n  defaultProfile(wallet: string, overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   * @param collectNFTId Type: uint256, Indexed: false\n   * @param from Type: address, Indexed: false\n   * @param to Type: address, Indexed: false\n   */\n  emitCollectNFTTransferEvent(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    collectNFTId: BigNumberish,\n    from: string,\n    to: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param followNFTId Type: uint256, Indexed: false\n   * @param from Type: address, Indexed: false\n   * @param to Type: address, Indexed: false\n   */\n  emitFollowNFTTransferEvent(\n    profileId: BigNumberish,\n    followNFTId: BigNumberish,\n    from: string,\n    to: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  exists(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileIds Type: uint256[], Indexed: false\n   * @param datas Type: bytes[], Indexed: false\n   */\n  follow(\n    profileIds: BigNumberish[],\n    datas: Arrayish[],\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  followWithSig(\n    vars: FollowWithSigRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  getApproved(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   */\n  getCollectModule(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   */\n  getCollectNFT(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getCollectNFTImpl(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   */\n  getContentURI(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   */\n  getDispatcher(profileId: BigNumberish, overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getDomainSeparator(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   */\n  getFollowModule(profileId: BigNumberish, overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   */\n  getFollowNFT(profileId: BigNumberish, overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getFollowNFTImpl(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   */\n  getFollowNFTURI(profileId: BigNumberish, overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getGovernance(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   */\n  getHandle(profileId: BigNumberish, overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   */\n  getProfile(profileId: BigNumberish, overrides?: ContractCallOverrides): Promise<ProfileResponse>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param handle Type: string, Indexed: false\n   */\n  getProfileIdByHandle(handle: string, overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   */\n  getPub(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<PublicationResponse>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   */\n  getPubCount(profileId: BigNumberish, overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   */\n  getPubPointer(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<GetPubPointerResponse>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   */\n  getPubType(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<number>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   */\n  getReferenceModule(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getState(overrides?: ContractCallOverrides): Promise<number>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param name Type: string, Indexed: false\n   * @param symbol Type: string, Indexed: false\n   * @param newGovernance Type: address, Indexed: false\n   */\n  initialize(\n    name: string,\n    symbol: string,\n    newGovernance: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param owner Type: address, Indexed: false\n   * @param operator Type: address, Indexed: false\n   */\n  isApprovedForAll(\n    owner: string,\n    operator: string,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param collectModule Type: address, Indexed: false\n   */\n  isCollectModuleWhitelisted(\n    collectModule: string,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param followModule Type: address, Indexed: false\n   */\n  isFollowModuleWhitelisted(\n    followModule: string,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileCreator Type: address, Indexed: false\n   */\n  isProfileCreatorWhitelisted(\n    profileCreator: string,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param referenceModule Type: address, Indexed: false\n   */\n  isReferenceModuleWhitelisted(\n    referenceModule: string,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  mintTimestampOf(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  mirror(\n    vars: MirrorRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  mirrorWithSig(\n    vars: MirrorWithSigRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  mirrorWithSig_Dispatcher(\n    vars: MirrorWithSig_DispatcherRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  name(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  ownerOf(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param spender Type: address, Indexed: false\n   * @param tokenId Type: uint256, Indexed: false\n   * @param sig Type: tuple, Indexed: false\n   */\n  permit(\n    spender: string,\n    tokenId: BigNumberish,\n    sig: PermitRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param owner Type: address, Indexed: false\n   * @param operator Type: address, Indexed: false\n   * @param approved Type: bool, Indexed: false\n   * @param sig Type: tuple, Indexed: false\n   */\n  permitForAll(\n    owner: string,\n    operator: string,\n    approved: boolean,\n    sig: PermitForAllRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  post(vars: PostRequest, overrides?: ContractTransactionOverrides): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  postWithSig(\n    vars: PostWithSigRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  postWithSig_Dispatcher(\n    vars: PostWithSig_DispatcherRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param from Type: address, Indexed: false\n   * @param to Type: address, Indexed: false\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  safeTransferFrom(\n    from: string,\n    to: string,\n    tokenId: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param from Type: address, Indexed: false\n   * @param to Type: address, Indexed: false\n   * @param tokenId Type: uint256, Indexed: false\n   * @param _data Type: bytes, Indexed: false\n   */\n  safeTransferFrom(\n    from: string,\n    to: string,\n    tokenId: BigNumberish,\n    _data: Arrayish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param operator Type: address, Indexed: false\n   * @param approved Type: bool, Indexed: false\n   */\n  setApprovalForAll(\n    operator: string,\n    approved: boolean,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   */\n  setDefaultProfile(\n    profileId: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  setDefaultProfileWithSig(\n    vars: SetDefaultProfileWithSigRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param dispatcher Type: address, Indexed: false\n   */\n  setDispatcher(\n    profileId: BigNumberish,\n    dispatcher: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  setDispatcherWithSig(\n    vars: SetDispatcherWithSigRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param newEmergencyAdmin Type: address, Indexed: false\n   */\n  setEmergencyAdmin(\n    newEmergencyAdmin: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param followModule Type: address, Indexed: false\n   * @param followModuleInitData Type: bytes, Indexed: false\n   */\n  setFollowModule(\n    profileId: BigNumberish,\n    followModule: string,\n    followModuleInitData: Arrayish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  setFollowModuleWithSig(\n    vars: SetFollowModuleWithSigRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param followNFTURI Type: string, Indexed: false\n   */\n  setFollowNFTURI(\n    profileId: BigNumberish,\n    followNFTURI: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  setFollowNFTURIWithSig(\n    vars: SetFollowNFTURIWithSigRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param newGovernance Type: address, Indexed: false\n   */\n  setGovernance(\n    newGovernance: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param imageURI Type: string, Indexed: false\n   */\n  setProfileImageURI(\n    profileId: BigNumberish,\n    imageURI: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param vars Type: tuple, Indexed: false\n   */\n  setProfileImageURIWithSig(\n    vars: SetProfileImageURIWithSigRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param newState Type: uint8, Indexed: false\n   */\n  setState(\n    newState: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param parameter0 Type: address, Indexed: false\n   */\n  sigNonces(parameter0: string, overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param interfaceId Type: bytes4, Indexed: false\n   */\n  supportsInterface(interfaceId: Arrayish, overrides?: ContractCallOverrides): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  symbol(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param index Type: uint256, Indexed: false\n   */\n  tokenByIndex(index: BigNumberish, overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  tokenDataOf(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<TokendataResponse>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param owner Type: address, Indexed: false\n   * @param index Type: uint256, Indexed: false\n   */\n  tokenOfOwnerByIndex(\n    owner: string,\n    index: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  tokenURI(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  totalSupply(overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param from Type: address, Indexed: false\n   * @param to Type: address, Indexed: false\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  transferFrom(\n    from: string,\n    to: string,\n    tokenId: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param collectModule Type: address, Indexed: false\n   * @param whitelist Type: bool, Indexed: false\n   */\n  whitelistCollectModule(\n    collectModule: string,\n    whitelist: boolean,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param followModule Type: address, Indexed: false\n   * @param whitelist Type: bool, Indexed: false\n   */\n  whitelistFollowModule(\n    followModule: string,\n    whitelist: boolean,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileCreator Type: address, Indexed: false\n   * @param whitelist Type: bool, Indexed: false\n   */\n  whitelistProfileCreator(\n    profileCreator: string,\n    whitelist: boolean,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param referenceModule Type: address, Indexed: false\n   * @param whitelist Type: bool, Indexed: false\n   */\n  whitelistReferenceModule(\n    referenceModule: string,\n    whitelist: boolean,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n}\n"
  },
  {
    "path": "momoka-node/src/evm/abi-types/LensHubV1Events.ts",
    "content": "import { EthersContractContextV5 } from 'ethereum-abi-types-generator';\nimport { BigNumber, BigNumberish, BytesLike as Arrayish } from 'ethers';\n\nexport type ContractContext = EthersContractContextV5<\n  LensHubV1Events,\n  LensHubEventsMethodNames,\n  LensHubEventsEventsContext,\n  LensHubEventsEvents\n>;\n\nexport declare type EventFilter = {\n  address?: string;\n  topics?: Array<string>;\n  fromBlock?: string | number;\n  toBlock?: string | number;\n};\n\nexport interface ContractTransactionOverrides {\n  /**\n   * The maximum units of gas for the transaction to use\n   */\n  gasLimit?: number;\n  /**\n   * The price (in wei) per unit of gas\n   */\n  gasPrice?: BigNumber | string | number | Promise<any>;\n  /**\n   * The nonce to use in the transaction\n   */\n  nonce?: number;\n  /**\n   * The amount to send with the transaction (i.e. msg.value)\n   */\n  value?: BigNumber | string | number | Promise<any>;\n  /**\n   * The chain ID (or network ID) to use\n   */\n  chainId?: number;\n}\n\nexport interface ContractCallOverrides {\n  /**\n   * The address to execute the call as\n   */\n  from?: string;\n  /**\n   * The maximum units of gas for the transaction to use\n   */\n  gasLimit?: number;\n}\nexport type LensHubEventsEvents =\n  | 'BaseInitialized'\n  | 'CollectModuleWhitelisted'\n  | 'CollectNFTDeployed'\n  | 'CollectNFTInitialized'\n  | 'CollectNFTTransferred'\n  | 'Collected'\n  | 'CommentCreated'\n  | 'DefaultProfileSet'\n  | 'DispatcherSet'\n  | 'EmergencyAdminSet'\n  | 'FeeModuleBaseConstructed'\n  | 'FollowModuleSet'\n  | 'FollowModuleWhitelisted'\n  | 'FollowNFTDelegatedPowerChanged'\n  | 'FollowNFTDeployed'\n  | 'FollowNFTInitialized'\n  | 'FollowNFTTransferred'\n  | 'FollowNFTURISet'\n  | 'Followed'\n  | 'FollowsApproved'\n  | 'FollowsToggled'\n  | 'GovernanceSet'\n  | 'MirrorCreated'\n  | 'ModuleBaseConstructed'\n  | 'ModuleGlobalsCurrencyWhitelisted'\n  | 'ModuleGlobalsGovernanceSet'\n  | 'ModuleGlobalsTreasuryFeeSet'\n  | 'ModuleGlobalsTreasurySet'\n  | 'PostCreated'\n  | 'ProfileCreated'\n  | 'ProfileCreatorWhitelisted'\n  | 'ProfileImageURISet'\n  | 'ProfileMetadataSet'\n  | 'ReferenceModuleWhitelisted'\n  | 'StateSet';\nexport interface LensHubEventsEventsContext {\n  BaseInitialized(...parameters: any): EventFilter;\n  CollectModuleWhitelisted(...parameters: any): EventFilter;\n  CollectNFTDeployed(...parameters: any): EventFilter;\n  CollectNFTInitialized(...parameters: any): EventFilter;\n  CollectNFTTransferred(...parameters: any): EventFilter;\n  Collected(...parameters: any): EventFilter;\n  CommentCreated(...parameters: any): EventFilter;\n  DefaultProfileSet(...parameters: any): EventFilter;\n  DispatcherSet(...parameters: any): EventFilter;\n  EmergencyAdminSet(...parameters: any): EventFilter;\n  FeeModuleBaseConstructed(...parameters: any): EventFilter;\n  FollowModuleSet(...parameters: any): EventFilter;\n  FollowModuleWhitelisted(...parameters: any): EventFilter;\n  FollowNFTDelegatedPowerChanged(...parameters: any): EventFilter;\n  FollowNFTDeployed(...parameters: any): EventFilter;\n  FollowNFTInitialized(...parameters: any): EventFilter;\n  FollowNFTTransferred(...parameters: any): EventFilter;\n  FollowNFTURISet(...parameters: any): EventFilter;\n  Followed(...parameters: any): EventFilter;\n  FollowsApproved(...parameters: any): EventFilter;\n  FollowsToggled(...parameters: any): EventFilter;\n  GovernanceSet(...parameters: any): EventFilter;\n  MirrorCreated(...parameters: any): EventFilter;\n  ModuleBaseConstructed(...parameters: any): EventFilter;\n  ModuleGlobalsCurrencyWhitelisted(...parameters: any): EventFilter;\n  ModuleGlobalsGovernanceSet(...parameters: any): EventFilter;\n  ModuleGlobalsTreasuryFeeSet(...parameters: any): EventFilter;\n  ModuleGlobalsTreasurySet(...parameters: any): EventFilter;\n  PostCreated(...parameters: any): EventFilter;\n  ProfileCreated(...parameters: any): EventFilter;\n  ProfileCreatorWhitelisted(...parameters: any): EventFilter;\n  ProfileImageURISet(...parameters: any): EventFilter;\n  ProfileMetadataSet(...parameters: any): EventFilter;\n  ReferenceModuleWhitelisted(...parameters: any): EventFilter;\n  StateSet(...parameters: any): EventFilter;\n}\nexport type LensHubEventsMethodNames = undefined;\nexport interface BaseInitializedEventEmittedResponse {\n  name: string;\n  symbol: string;\n  timestamp: BigNumberish;\n}\nexport interface CollectModuleWhitelistedEventEmittedResponse {\n  collectModule: string;\n  whitelisted: boolean;\n  timestamp: BigNumberish;\n}\nexport interface CollectNFTDeployedEventEmittedResponse {\n  profileId: BigNumberish;\n  pubId: BigNumberish;\n  collectNFT: string;\n  timestamp: BigNumberish;\n}\nexport interface CollectNFTInitializedEventEmittedResponse {\n  profileId: BigNumberish;\n  pubId: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface CollectNFTTransferredEventEmittedResponse {\n  profileId: BigNumberish;\n  pubId: BigNumberish;\n  collectNFTId: BigNumberish;\n  from: string;\n  to: string;\n  timestamp: BigNumberish;\n}\nexport interface CollectedEventEmittedResponse {\n  collector: string;\n  profileId: BigNumberish;\n  pubId: BigNumberish;\n  rootProfileId: BigNumberish;\n  rootPubId: BigNumberish;\n  collectModuleData: Arrayish;\n  timestamp: BigNumberish;\n}\nexport interface CommentCreatedEventEmittedResponse {\n  profileId: BigNumberish;\n  pubId: BigNumberish;\n  contentURI: string;\n  profileIdPointed: BigNumberish;\n  pubIdPointed: BigNumberish;\n  referenceModuleData: Arrayish;\n  collectModule: string;\n  collectModuleReturnData: Arrayish;\n  referenceModule: string;\n  referenceModuleReturnData: Arrayish;\n  timestamp: BigNumberish;\n}\nexport interface DefaultProfileSetEventEmittedResponse {\n  wallet: string;\n  profileId: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface DispatcherSetEventEmittedResponse {\n  profileId: BigNumberish;\n  dispatcher: string;\n  timestamp: BigNumberish;\n}\nexport interface EmergencyAdminSetEventEmittedResponse {\n  caller: string;\n  oldEmergencyAdmin: string;\n  newEmergencyAdmin: string;\n  timestamp: BigNumberish;\n}\nexport interface FeeModuleBaseConstructedEventEmittedResponse {\n  moduleGlobals: string;\n  timestamp: BigNumberish;\n}\nexport interface FollowModuleSetEventEmittedResponse {\n  profileId: BigNumberish;\n  followModule: string;\n  followModuleReturnData: Arrayish;\n  timestamp: BigNumberish;\n}\nexport interface FollowModuleWhitelistedEventEmittedResponse {\n  followModule: string;\n  whitelisted: boolean;\n  timestamp: BigNumberish;\n}\nexport interface FollowNFTDelegatedPowerChangedEventEmittedResponse {\n  delegate: string;\n  newPower: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface FollowNFTDeployedEventEmittedResponse {\n  profileId: BigNumberish;\n  followNFT: string;\n  timestamp: BigNumberish;\n}\nexport interface FollowNFTInitializedEventEmittedResponse {\n  profileId: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface FollowNFTTransferredEventEmittedResponse {\n  profileId: BigNumberish;\n  followNFTId: BigNumberish;\n  from: string;\n  to: string;\n  timestamp: BigNumberish;\n}\nexport interface FollowNFTURISetEventEmittedResponse {\n  profileId: BigNumberish;\n  followNFTURI: string;\n  timestamp: BigNumberish;\n}\nexport interface FollowedEventEmittedResponse {\n  follower: string;\n  profileIds: BigNumberish[];\n  followModuleDatas: Arrayish[];\n  timestamp: BigNumberish;\n}\nexport interface FollowsApprovedEventEmittedResponse {\n  owner: string;\n  profileId: BigNumberish;\n  addresses: string[];\n  approved: boolean[];\n  timestamp: BigNumberish;\n}\nexport interface FollowsToggledEventEmittedResponse {\n  owner: string;\n  profileIds: BigNumberish[];\n  enabled: boolean[];\n  timestamp: BigNumberish;\n}\nexport interface GovernanceSetEventEmittedResponse {\n  caller: string;\n  prevGovernance: string;\n  newGovernance: string;\n  timestamp: BigNumberish;\n}\nexport interface MirrorCreatedEventEmittedResponse {\n  profileId: BigNumberish;\n  pubId: BigNumberish;\n  profileIdPointed: BigNumberish;\n  pubIdPointed: BigNumberish;\n  referenceModuleData: Arrayish;\n  referenceModule: string;\n  referenceModuleReturnData: Arrayish;\n  timestamp: BigNumberish;\n}\nexport interface ModuleBaseConstructedEventEmittedResponse {\n  hub: string;\n  timestamp: BigNumberish;\n}\nexport interface ModuleGlobalsCurrencyWhitelistedEventEmittedResponse {\n  currency: string;\n  prevWhitelisted: boolean;\n  whitelisted: boolean;\n  timestamp: BigNumberish;\n}\nexport interface ModuleGlobalsGovernanceSetEventEmittedResponse {\n  prevGovernance: string;\n  newGovernance: string;\n  timestamp: BigNumberish;\n}\nexport interface ModuleGlobalsTreasuryFeeSetEventEmittedResponse {\n  prevTreasuryFee: BigNumberish;\n  newTreasuryFee: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface ModuleGlobalsTreasurySetEventEmittedResponse {\n  prevTreasury: string;\n  newTreasury: string;\n  timestamp: BigNumberish;\n}\nexport interface PostCreatedEventEmittedResponse {\n  profileId: BigNumberish;\n  pubId: BigNumberish;\n  contentURI: string;\n  collectModule: string;\n  collectModuleReturnData: Arrayish;\n  referenceModule: string;\n  referenceModuleReturnData: Arrayish;\n  timestamp: BigNumberish;\n}\nexport interface ProfileCreatedEventEmittedResponse {\n  profileId: BigNumberish;\n  creator: string;\n  to: string;\n  handle: string;\n  imageURI: string;\n  followModule: string;\n  followModuleReturnData: Arrayish;\n  followNFTURI: string;\n  timestamp: BigNumberish;\n}\nexport interface ProfileCreatorWhitelistedEventEmittedResponse {\n  profileCreator: string;\n  whitelisted: boolean;\n  timestamp: BigNumberish;\n}\nexport interface ProfileImageURISetEventEmittedResponse {\n  profileId: BigNumberish;\n  imageURI: string;\n  timestamp: BigNumberish;\n}\nexport interface ProfileMetadataSetEventEmittedResponse {\n  profileId: BigNumberish;\n  metadata: string;\n  timestamp: BigNumberish;\n}\nexport interface ReferenceModuleWhitelistedEventEmittedResponse {\n  referenceModule: string;\n  whitelisted: boolean;\n  timestamp: BigNumberish;\n}\nexport interface StateSetEventEmittedResponse {\n  caller: string;\n  prevState: BigNumberish;\n  newState: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface LensHubV1Events {}\n"
  },
  {
    "path": "momoka-node/src/evm/abi-types/LensHubV2.ts",
    "content": "import { ContractTransaction, BytesLike as Arrayish, BigNumber, BigNumberish } from 'ethers';\nimport { EthersContractContextV5 } from 'ethereum-abi-types-generator';\n\nexport type ContractContext = EthersContractContextV5<\n  LensHub,\n  LensHubMethodNames,\n  LensHubEventsContext,\n  LensHubEvents\n>;\n\nexport declare interface EventFilter {\n  address?: string;\n  topics?: Array<string>;\n  fromBlock?: string | number;\n  toBlock?: string | number;\n}\n\nexport interface ContractTransactionOverrides {\n  /**\n   * The maximum units of gas for the transaction to use\n   */\n  gasLimit?: number;\n  /**\n   * The price (in wei) per unit of gas\n   */\n  gasPrice?: BigNumber | string | number | Promise<any>;\n  /**\n   * The nonce to use in the transaction\n   */\n  nonce?: number;\n  /**\n   * The amount to send with the transaction (i.e. msg.value)\n   */\n  value?: BigNumber | string | number | Promise<any>;\n  /**\n   * The chain ID (or network ID) to use\n   */\n  chainId?: number;\n}\n\nexport interface ContractCallOverrides {\n  /**\n   * The address to execute the call as\n   */\n  from?: string;\n  /**\n   * The maximum units of gas for the transaction to use\n   */\n  gasLimit?: number;\n  /**\n   * The block tag!\n   */\n  blockTag?: string | number;\n}\nexport type LensHubEvents = 'Approval' | 'ApprovalForAll' | 'Transfer';\nexport interface LensHubEventsContext {\n  Approval(...parameters: any): EventFilter;\n  ApprovalForAll(...parameters: any): EventFilter;\n  Transfer(...parameters: any): EventFilter;\n}\nexport type LensHubMethodNames =\n  | 'new'\n  | 'DANGER__disableTokenGuardian'\n  | 'act'\n  | 'actWithSig'\n  | 'approve'\n  | 'balanceOf'\n  | 'batchMigrateFollowModules'\n  | 'batchMigrateFollowers'\n  | 'batchMigrateFollows'\n  | 'batchMigrateProfiles'\n  | 'burn'\n  | 'changeDelegatedExecutorsConfig'\n  | 'changeDelegatedExecutorsConfigWithSig'\n  | 'collectLegacy'\n  | 'collectLegacyWithSig'\n  | 'comment'\n  | 'commentWithSig'\n  | 'createProfile'\n  | 'emitCollectNFTTransferEvent'\n  | 'emitUnfollowedEvent'\n  | 'enableTokenGuardian'\n  | 'exists'\n  | 'follow'\n  | 'followWithSig'\n  | 'getApproved'\n  | 'getContentURI'\n  | 'getDelegatedExecutorsConfigNumber'\n  | 'getDelegatedExecutorsMaxConfigNumberSet'\n  | 'getDelegatedExecutorsPrevConfigNumber'\n  | 'getDomainSeparator'\n  | 'getFollowNFTImpl'\n  | 'getGovernance'\n  | 'getLegacyCollectNFTImpl'\n  | 'getModuleRegistry'\n  | 'getProfile'\n  | 'getProfileIdByHandleHash'\n  | 'getPublication'\n  | 'getPublicationType'\n  | 'getState'\n  | 'getTokenGuardianDisablingTimestamp'\n  | 'getTreasury'\n  | 'getTreasuryData'\n  | 'getTreasuryFee'\n  | 'initialize'\n  | 'isActionModuleEnabledInPublication'\n  | 'isApprovedForAll'\n  | 'isBlocked'\n  | 'isDelegatedExecutorApproved'\n  | 'isFollowing'\n  | 'isProfileCreatorWhitelisted'\n  | 'mintTimestampOf'\n  | 'mirror'\n  | 'mirrorWithSig'\n  | 'name'\n  | 'nonces'\n  | 'ownerOf'\n  | 'post'\n  | 'postWithSig'\n  | 'quote'\n  | 'quoteWithSig'\n  | 'royaltyInfo'\n  | 'safeTransferFrom'\n  | 'setApprovalForAll'\n  | 'setBlockStatus'\n  | 'setBlockStatusWithSig'\n  | 'setEmergencyAdmin'\n  | 'setFollowModule'\n  | 'setFollowModuleWithSig'\n  | 'setGovernance'\n  | 'setMigrationAdmins'\n  | 'setProfileMetadataURI'\n  | 'setProfileMetadataURIWithSig'\n  | 'setRoyalty'\n  | 'setState'\n  | 'setTreasury'\n  | 'setTreasuryFee'\n  | 'supportsInterface'\n  | 'symbol'\n  | 'tokenDataOf'\n  | 'tokenURI'\n  | 'totalSupply'\n  | 'transferFrom'\n  | 'unfollow'\n  | 'unfollowWithSig'\n  | 'whitelistProfileCreator';\nexport interface MigrationParamsRequest {\n  lensHandlesAddress: string;\n  tokenHandleRegistryAddress: string;\n  legacyFeeFollowModule: string;\n  legacyProfileFollowModule: string;\n  newFeeFollowModule: string;\n  migrationAdmin: string;\n}\nexport interface ApprovalEventEmittedResponse {\n  owner: string;\n  approved: string;\n  tokenId: BigNumberish;\n}\nexport interface ApprovalForAllEventEmittedResponse {\n  owner: string;\n  operator: string;\n  approved: boolean;\n}\nexport interface TransferEventEmittedResponse {\n  from: string;\n  to: string;\n  tokenId: BigNumberish;\n}\nexport interface PublicationActionParamsRequest {\n  publicationActedProfileId: BigNumberish;\n  publicationActedId: BigNumberish;\n  actorProfileId: BigNumberish;\n  referrerProfileIds: BigNumberish[];\n  referrerPubIds: BigNumberish[];\n  actionModuleAddress: string;\n  actionModuleData: Arrayish;\n}\nexport interface SignatureRequest {\n  signer: string;\n  v: BigNumberish;\n  r: Arrayish;\n  s: Arrayish;\n  deadline: BigNumberish;\n}\nexport interface CollectParamsRequest {\n  publicationCollectedProfileId: BigNumberish;\n  publicationCollectedId: BigNumberish;\n  collectorProfileId: BigNumberish;\n  referrerProfileId: BigNumberish;\n  referrerPubId: BigNumberish;\n  collectModuleData: Arrayish;\n}\nexport interface CommentParamsRequest {\n  profileId: BigNumberish;\n  contentURI: string;\n  pointedProfileId: BigNumberish;\n  pointedPubId: BigNumberish;\n  referrerProfileIds: BigNumberish[];\n  referrerPubIds: BigNumberish[];\n  referenceModuleData: Arrayish;\n  actionModules: string[];\n  actionModulesInitDatas: Arrayish[];\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n}\nexport interface CreateProfileParamsRequest {\n  to: string;\n  followModule: string;\n  followModuleInitData: Arrayish;\n}\nexport interface ProfileResponse {\n  pubCount: BigNumber;\n  0: BigNumber;\n  followModule: string;\n  1: string;\n  followNFT: string;\n  2: string;\n  __DEPRECATED__handle: string;\n  3: string;\n  __DEPRECATED__imageURI: string;\n  4: string;\n  __DEPRECATED__followNFTURI: string;\n  5: string;\n  metadataURI: string;\n  6: string;\n}\nexport interface PublicationmemoryResponse {\n  pointedProfileId: BigNumber;\n  0: BigNumber;\n  pointedPubId: BigNumber;\n  1: BigNumber;\n  contentURI: string;\n  2: string;\n  referenceModule: string;\n  3: string;\n  __DEPRECATED__collectModule: string;\n  4: string;\n  __DEPRECATED__collectNFT: string;\n  5: string;\n  pubType: number;\n  6: number;\n  rootProfileId: BigNumber;\n  7: BigNumber;\n  rootPubId: BigNumber;\n  8: BigNumber;\n}\nexport interface GetTreasuryDataResponse {\n  result0: string;\n  0: string;\n  result1: number;\n  1: number;\n  length: 2;\n}\nexport interface MirrorParamsRequest {\n  profileId: BigNumberish;\n  metadataURI: string;\n  pointedProfileId: BigNumberish;\n  pointedPubId: BigNumberish;\n  referrerProfileIds: BigNumberish[];\n  referrerPubIds: BigNumberish[];\n  referenceModuleData: Arrayish;\n}\nexport interface PostParamsRequest {\n  profileId: BigNumberish;\n  contentURI: string;\n  actionModules: string[];\n  actionModulesInitDatas: Arrayish[];\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n}\nexport interface QuoteParamsRequest {\n  profileId: BigNumberish;\n  contentURI: string;\n  pointedProfileId: BigNumberish;\n  pointedPubId: BigNumberish;\n  referrerProfileIds: BigNumberish[];\n  referrerPubIds: BigNumberish[];\n  referenceModuleData: Arrayish;\n  actionModules: string[];\n  actionModulesInitDatas: Arrayish[];\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n}\nexport interface RoyaltyInfoResponse {\n  result0: string;\n  0: string;\n  result1: BigNumber;\n  1: BigNumber;\n  length: 2;\n}\nexport interface TokendataResponse {\n  owner: string;\n  0: string;\n  mintTimestamp: BigNumber;\n  1: BigNumber;\n}\nexport interface LensHub {\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: constructor\n   * @param followNFTImpl Type: address, Indexed: false\n   * @param collectNFTImpl Type: address, Indexed: false\n   * @param moduleRegistry Type: address, Indexed: false\n   * @param tokenGuardianCooldown Type: uint256, Indexed: false\n   * @param migrationParams Type: tuple, Indexed: false\n   */\n  'new'(\n    followNFTImpl: string,\n    collectNFTImpl: string,\n    moduleRegistry: string,\n    tokenGuardianCooldown: BigNumberish,\n    migrationParams: MigrationParamsRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   */\n  DANGER__disableTokenGuardian(\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param publicationActionParams Type: tuple, Indexed: false\n   */\n  act(\n    publicationActionParams: PublicationActionParamsRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param publicationActionParams Type: tuple, Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  actWithSig(\n    publicationActionParams: PublicationActionParamsRequest,\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param to Type: address, Indexed: false\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  approve(\n    to: string,\n    tokenId: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param owner Type: address, Indexed: false\n   */\n  balanceOf(owner: string, overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileIds Type: uint256[], Indexed: false\n   */\n  batchMigrateFollowModules(\n    profileIds: BigNumberish[],\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param followerProfileIds Type: uint256[], Indexed: false\n   * @param idOfProfileFollowed Type: uint256, Indexed: false\n   * @param followTokenIds Type: uint256[], Indexed: false\n   */\n  batchMigrateFollowers(\n    followerProfileIds: BigNumberish[],\n    idOfProfileFollowed: BigNumberish,\n    followTokenIds: BigNumberish[],\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param followerProfileId Type: uint256, Indexed: false\n   * @param idsOfProfileFollowed Type: uint256[], Indexed: false\n   * @param followTokenIds Type: uint256[], Indexed: false\n   */\n  batchMigrateFollows(\n    followerProfileId: BigNumberish,\n    idsOfProfileFollowed: BigNumberish[],\n    followTokenIds: BigNumberish[],\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileIds Type: uint256[], Indexed: false\n   */\n  batchMigrateProfiles(\n    profileIds: BigNumberish[],\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  burn(\n    tokenId: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param delegatorProfileId Type: uint256, Indexed: false\n   * @param delegatedExecutors Type: address[], Indexed: false\n   * @param approvals Type: bool[], Indexed: false\n   * @param configNumber Type: uint64, Indexed: false\n   * @param switchToGivenConfig Type: bool, Indexed: false\n   */\n  changeDelegatedExecutorsConfig(\n    delegatorProfileId: BigNumberish,\n    delegatedExecutors: string[],\n    approvals: boolean[],\n    configNumber: BigNumberish,\n    switchToGivenConfig: boolean,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param delegatorProfileId Type: uint256, Indexed: false\n   * @param delegatedExecutors Type: address[], Indexed: false\n   * @param approvals Type: bool[], Indexed: false\n   */\n  changeDelegatedExecutorsConfig(\n    delegatorProfileId: BigNumberish,\n    delegatedExecutors: string[],\n    approvals: boolean[],\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param delegatorProfileId Type: uint256, Indexed: false\n   * @param delegatedExecutors Type: address[], Indexed: false\n   * @param approvals Type: bool[], Indexed: false\n   * @param configNumber Type: uint64, Indexed: false\n   * @param switchToGivenConfig Type: bool, Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  changeDelegatedExecutorsConfigWithSig(\n    delegatorProfileId: BigNumberish,\n    delegatedExecutors: string[],\n    approvals: boolean[],\n    configNumber: BigNumberish,\n    switchToGivenConfig: boolean,\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param collectParams Type: tuple, Indexed: false\n   */\n  collectLegacy(\n    collectParams: CollectParamsRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param collectParams Type: tuple, Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  collectLegacyWithSig(\n    collectParams: CollectParamsRequest,\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param commentParams Type: tuple, Indexed: false\n   */\n  comment(\n    commentParams: CommentParamsRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param commentParams Type: tuple, Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  commentWithSig(\n    commentParams: CommentParamsRequest,\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param createProfileParams Type: tuple, Indexed: false\n   */\n  createProfile(\n    createProfileParams: CreateProfileParamsRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   * @param collectNFTId Type: uint256, Indexed: false\n   * @param from Type: address, Indexed: false\n   * @param to Type: address, Indexed: false\n   */\n  emitCollectNFTTransferEvent(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    collectNFTId: BigNumberish,\n    from: string,\n    to: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param unfollowerProfileId Type: uint256, Indexed: false\n   * @param idOfProfileUnfollowed Type: uint256, Indexed: false\n   * @param transactionExecutor Type: address, Indexed: false\n   */\n  emitUnfollowedEvent(\n    unfollowerProfileId: BigNumberish,\n    idOfProfileUnfollowed: BigNumberish,\n    transactionExecutor: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   */\n  enableTokenGuardian(overrides?: ContractTransactionOverrides): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  exists(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param followerProfileId Type: uint256, Indexed: false\n   * @param idsOfProfilesToFollow Type: uint256[], Indexed: false\n   * @param followTokenIds Type: uint256[], Indexed: false\n   * @param datas Type: bytes[], Indexed: false\n   */\n  follow(\n    followerProfileId: BigNumberish,\n    idsOfProfilesToFollow: BigNumberish[],\n    followTokenIds: BigNumberish[],\n    datas: Arrayish[],\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param followerProfileId Type: uint256, Indexed: false\n   * @param idsOfProfilesToFollow Type: uint256[], Indexed: false\n   * @param followTokenIds Type: uint256[], Indexed: false\n   * @param datas Type: bytes[], Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  followWithSig(\n    followerProfileId: BigNumberish,\n    idsOfProfilesToFollow: BigNumberish[],\n    followTokenIds: BigNumberish[],\n    datas: Arrayish[],\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  getApproved(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   */\n  getContentURI(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param delegatorProfileId Type: uint256, Indexed: false\n   */\n  getDelegatedExecutorsConfigNumber(\n    delegatorProfileId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param delegatorProfileId Type: uint256, Indexed: false\n   */\n  getDelegatedExecutorsMaxConfigNumberSet(\n    delegatorProfileId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param delegatorProfileId Type: uint256, Indexed: false\n   */\n  getDelegatedExecutorsPrevConfigNumber(\n    delegatorProfileId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getDomainSeparator(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getFollowNFTImpl(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getGovernance(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getLegacyCollectNFTImpl(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getModuleRegistry(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   */\n  getProfile(profileId: BigNumberish, overrides?: ContractCallOverrides): Promise<ProfileResponse>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param handleHash Type: bytes32, Indexed: false\n   */\n  getProfileIdByHandleHash(\n    handleHash: Arrayish,\n    overrides?: ContractCallOverrides\n  ): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: pure\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   */\n  getPublication(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<PublicationmemoryResponse>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   */\n  getPublicationType(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<number>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getState(overrides?: ContractCallOverrides): Promise<number>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param wallet Type: address, Indexed: false\n   */\n  getTokenGuardianDisablingTimestamp(\n    wallet: string,\n    overrides?: ContractCallOverrides\n  ): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getTreasury(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getTreasuryData(overrides?: ContractCallOverrides): Promise<GetTreasuryDataResponse>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  getTreasuryFee(overrides?: ContractCallOverrides): Promise<number>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param name Type: string, Indexed: false\n   * @param symbol Type: string, Indexed: false\n   * @param newGovernance Type: address, Indexed: false\n   */\n  initialize(\n    name: string,\n    symbol: string,\n    newGovernance: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param pubId Type: uint256, Indexed: false\n   * @param module Type: address, Indexed: false\n   */\n  isActionModuleEnabledInPublication(\n    profileId: BigNumberish,\n    pubId: BigNumberish,\n    module: string,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param owner Type: address, Indexed: false\n   * @param operator Type: address, Indexed: false\n   */\n  isApprovedForAll(\n    owner: string,\n    operator: string,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param byProfileId Type: uint256, Indexed: false\n   */\n  isBlocked(\n    profileId: BigNumberish,\n    byProfileId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param delegatorProfileId Type: uint256, Indexed: false\n   * @param delegatedExecutor Type: address, Indexed: false\n   */\n  isDelegatedExecutorApproved(\n    delegatorProfileId: BigNumberish,\n    delegatedExecutor: string,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param delegatorProfileId Type: uint256, Indexed: false\n   * @param delegatedExecutor Type: address, Indexed: false\n   * @param configNumber Type: uint64, Indexed: false\n   */\n  isDelegatedExecutorApproved(\n    delegatorProfileId: BigNumberish,\n    delegatedExecutor: string,\n    configNumber: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param followerProfileId Type: uint256, Indexed: false\n   * @param followedProfileId Type: uint256, Indexed: false\n   */\n  isFollowing(\n    followerProfileId: BigNumberish,\n    followedProfileId: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param profileCreator Type: address, Indexed: false\n   */\n  isProfileCreatorWhitelisted(\n    profileCreator: string,\n    overrides?: ContractCallOverrides\n  ): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  mintTimestampOf(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param mirrorParams Type: tuple, Indexed: false\n   */\n  mirror(\n    mirrorParams: MirrorParamsRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param mirrorParams Type: tuple, Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  mirrorWithSig(\n    mirrorParams: MirrorParamsRequest,\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  name(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param signer Type: address, Indexed: false\n   */\n  nonces(signer: string, overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  ownerOf(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param postParams Type: tuple, Indexed: false\n   */\n  post(\n    postParams: PostParamsRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param postParams Type: tuple, Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  postWithSig(\n    postParams: PostParamsRequest,\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param quoteParams Type: tuple, Indexed: false\n   */\n  quote(\n    quoteParams: QuoteParamsRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param quoteParams Type: tuple, Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  quoteWithSig(\n    quoteParams: QuoteParamsRequest,\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   * @param salePrice Type: uint256, Indexed: false\n   */\n  royaltyInfo(\n    tokenId: BigNumberish,\n    salePrice: BigNumberish,\n    overrides?: ContractCallOverrides\n  ): Promise<RoyaltyInfoResponse>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param from Type: address, Indexed: false\n   * @param to Type: address, Indexed: false\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  safeTransferFrom(\n    from: string,\n    to: string,\n    tokenId: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param from Type: address, Indexed: false\n   * @param to Type: address, Indexed: false\n   * @param tokenId Type: uint256, Indexed: false\n   * @param _data Type: bytes, Indexed: false\n   */\n  safeTransferFrom(\n    from: string,\n    to: string,\n    tokenId: BigNumberish,\n    _data: Arrayish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param operator Type: address, Indexed: false\n   * @param approved Type: bool, Indexed: false\n   */\n  setApprovalForAll(\n    operator: string,\n    approved: boolean,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param byProfileId Type: uint256, Indexed: false\n   * @param idsOfProfilesToSetBlockStatus Type: uint256[], Indexed: false\n   * @param blockStatus Type: bool[], Indexed: false\n   */\n  setBlockStatus(\n    byProfileId: BigNumberish,\n    idsOfProfilesToSetBlockStatus: BigNumberish[],\n    blockStatus: boolean[],\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param byProfileId Type: uint256, Indexed: false\n   * @param idsOfProfilesToSetBlockStatus Type: uint256[], Indexed: false\n   * @param blockStatus Type: bool[], Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  setBlockStatusWithSig(\n    byProfileId: BigNumberish,\n    idsOfProfilesToSetBlockStatus: BigNumberish[],\n    blockStatus: boolean[],\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param newEmergencyAdmin Type: address, Indexed: false\n   */\n  setEmergencyAdmin(\n    newEmergencyAdmin: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param followModule Type: address, Indexed: false\n   * @param followModuleInitData Type: bytes, Indexed: false\n   */\n  setFollowModule(\n    profileId: BigNumberish,\n    followModule: string,\n    followModuleInitData: Arrayish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param followModule Type: address, Indexed: false\n   * @param followModuleInitData Type: bytes, Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  setFollowModuleWithSig(\n    profileId: BigNumberish,\n    followModule: string,\n    followModuleInitData: Arrayish,\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param newGovernance Type: address, Indexed: false\n   */\n  setGovernance(\n    newGovernance: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param migrationAdmins Type: address[], Indexed: false\n   * @param whitelisted Type: bool, Indexed: false\n   */\n  setMigrationAdmins(\n    migrationAdmins: string[],\n    whitelisted: boolean,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param metadataURI Type: string, Indexed: false\n   */\n  setProfileMetadataURI(\n    profileId: BigNumberish,\n    metadataURI: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileId Type: uint256, Indexed: false\n   * @param metadataURI Type: string, Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  setProfileMetadataURIWithSig(\n    profileId: BigNumberish,\n    metadataURI: string,\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param royaltiesInBasisPoints Type: uint256, Indexed: false\n   */\n  setRoyalty(\n    royaltiesInBasisPoints: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param newState Type: uint8, Indexed: false\n   */\n  setState(\n    newState: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param newTreasury Type: address, Indexed: false\n   */\n  setTreasury(\n    newTreasury: string,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param newTreasuryFee Type: uint16, Indexed: false\n   */\n  setTreasuryFee(\n    newTreasuryFee: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param interfaceId Type: bytes4, Indexed: false\n   */\n  supportsInterface(interfaceId: Arrayish, overrides?: ContractCallOverrides): Promise<boolean>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  symbol(overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  tokenDataOf(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<TokendataResponse>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  tokenURI(tokenId: BigNumberish, overrides?: ContractCallOverrides): Promise<string>;\n  /**\n   * Payable: false\n   * Constant: true\n   * StateMutability: view\n   * Type: function\n   */\n  totalSupply(overrides?: ContractCallOverrides): Promise<BigNumber>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param from Type: address, Indexed: false\n   * @param to Type: address, Indexed: false\n   * @param tokenId Type: uint256, Indexed: false\n   */\n  transferFrom(\n    from: string,\n    to: string,\n    tokenId: BigNumberish,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param unfollowerProfileId Type: uint256, Indexed: false\n   * @param idsOfProfilesToUnfollow Type: uint256[], Indexed: false\n   */\n  unfollow(\n    unfollowerProfileId: BigNumberish,\n    idsOfProfilesToUnfollow: BigNumberish[],\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param unfollowerProfileId Type: uint256, Indexed: false\n   * @param idsOfProfilesToUnfollow Type: uint256[], Indexed: false\n   * @param signature Type: tuple, Indexed: false\n   */\n  unfollowWithSig(\n    unfollowerProfileId: BigNumberish,\n    idsOfProfilesToUnfollow: BigNumberish[],\n    signature: SignatureRequest,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n  /**\n   * Payable: false\n   * Constant: false\n   * StateMutability: nonpayable\n   * Type: function\n   * @param profileCreator Type: address, Indexed: false\n   * @param whitelist Type: bool, Indexed: false\n   */\n  whitelistProfileCreator(\n    profileCreator: string,\n    whitelist: boolean,\n    overrides?: ContractTransactionOverrides\n  ): Promise<ContractTransaction>;\n}\n"
  },
  {
    "path": "momoka-node/src/evm/abi-types/LensHubV2Events.ts",
    "content": "import { EthersContractContextV5 } from 'ethereum-abi-types-generator';\nimport { BytesLike as Arrayish, BigNumber, BigNumberish } from 'ethers';\n\nexport type ContractContext = EthersContractContextV5<\n  LensHubEvents,\n  LensHubEventsMethodNames,\n  LensHubEventsEventsContext,\n  LensHubEventsEvents\n>;\n\nexport declare interface EventFilter {\n  address?: string;\n  topics?: Array<string>;\n  fromBlock?: string | number;\n  toBlock?: string | number;\n}\n\nexport interface ContractTransactionOverrides {\n  /**\n   * The maximum units of gas for the transaction to use\n   */\n  gasLimit?: number;\n  /**\n   * The price (in wei) per unit of gas\n   */\n  gasPrice?: BigNumber | string | number | Promise<any>;\n  /**\n   * The nonce to use in the transaction\n   */\n  nonce?: number;\n  /**\n   * The amount to send with the transaction (i.e. msg.value)\n   */\n  value?: BigNumber | string | number | Promise<any>;\n  /**\n   * The chain ID (or network ID) to use\n   */\n  chainId?: number;\n}\n\nexport interface ContractCallOverrides {\n  /**\n   * The address to execute the call as\n   */\n  from?: string;\n  /**\n   * The maximum units of gas for the transaction to use\n   */\n  gasLimit?: number;\n}\nexport type LensHubEventsEvents =\n  | 'Acted'\n  | 'ActionModuleWhitelisted'\n  | 'BaseInitialized'\n  | 'Blocked'\n  | 'CollectNFTDeployed'\n  | 'CollectNFTTransferred'\n  | 'Collected'\n  | 'CommentCreated'\n  | 'DelegatedExecutorsConfigApplied'\n  | 'DelegatedExecutorsConfigChanged'\n  | 'EmergencyAdminSet'\n  | 'FollowModuleSet'\n  | 'FollowModuleWhitelisted'\n  | 'FollowNFTDeployed'\n  | 'Followed'\n  | 'GovernanceSet'\n  | 'MirrorCreated'\n  | 'ModuleGlobalsCurrencyWhitelisted'\n  | 'ModuleGlobalsGovernanceSet'\n  | 'ModuleGlobalsTreasuryFeeSet'\n  | 'ModuleGlobalsTreasurySet'\n  | 'PostCreated'\n  | 'ProfileCreated'\n  | 'ProfileCreatorWhitelisted'\n  | 'ProfileMetadataSet'\n  | 'QuoteCreated'\n  | 'ReferenceModuleWhitelisted'\n  | 'StateSet'\n  | 'TokenGuardianStateChanged'\n  | 'Unblocked'\n  | 'Unfollowed'\n  | 'NonceUpdated'\n  | 'LensUpgradeVersion'\n  | 'CollectedLegacy';\nexport interface LensHubEventsEventsContext {\n  Acted(...parameters: any): EventFilter;\n  ActionModuleWhitelisted(...parameters: any): EventFilter;\n  BaseInitialized(...parameters: any): EventFilter;\n  Blocked(...parameters: any): EventFilter;\n  CollectNFTDeployed(...parameters: any): EventFilter;\n  CollectNFTTransferred(...parameters: any): EventFilter;\n  Collected(...parameters: any): EventFilter;\n  CommentCreated(...parameters: any): EventFilter;\n  DelegatedExecutorsConfigApplied(...parameters: any): EventFilter;\n  DelegatedExecutorsConfigChanged(...parameters: any): EventFilter;\n  EmergencyAdminSet(...parameters: any): EventFilter;\n  FollowModuleSet(...parameters: any): EventFilter;\n  FollowModuleWhitelisted(...parameters: any): EventFilter;\n  FollowNFTDeployed(...parameters: any): EventFilter;\n  Followed(...parameters: any): EventFilter;\n  GovernanceSet(...parameters: any): EventFilter;\n  MirrorCreated(...parameters: any): EventFilter;\n  ModuleGlobalsCurrencyWhitelisted(...parameters: any): EventFilter;\n  ModuleGlobalsGovernanceSet(...parameters: any): EventFilter;\n  ModuleGlobalsTreasuryFeeSet(...parameters: any): EventFilter;\n  ModuleGlobalsTreasurySet(...parameters: any): EventFilter;\n  PostCreated(...parameters: any): EventFilter;\n  ProfileCreated(...parameters: any): EventFilter;\n  ProfileCreatorWhitelisted(...parameters: any): EventFilter;\n  ProfileMetadataSet(...parameters: any): EventFilter;\n  QuoteCreated(...parameters: any): EventFilter;\n  ReferenceModuleWhitelisted(...parameters: any): EventFilter;\n  StateSet(...parameters: any): EventFilter;\n  TokenGuardianStateChanged(...parameters: any): EventFilter;\n  Unblocked(...parameters: any): EventFilter;\n  Unfollowed(...parameters: any): EventFilter;\n  NonceUpdated(...parameters: any): EventFilter;\n  LensUpgradeVersion(...parameters: any): EventFilter;\n  CollectedLegacy(...parameters: any): EventFilter;\n}\nexport type LensHubEventsMethodNames = undefined;\nexport interface PublicationActionParamsEventEmittedResponse {\n  publicationActedProfileId: BigNumberish;\n  publicationActedId: BigNumberish;\n  actorProfileId: BigNumberish;\n  referrerProfileIds: BigNumberish[];\n  referrerPubIds: BigNumberish[];\n  actionModuleAddress: string;\n  actionModuleData: Arrayish;\n}\nexport interface ActedEventEmittedResponse {\n  publicationActionParams: PublicationActionParamsEventEmittedResponse;\n  actionModuleReturnData: Arrayish;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface ActionModuleWhitelistedEventEmittedResponse {\n  actionModule: string;\n  id: BigNumberish;\n  whitelisted: boolean;\n  timestamp: BigNumberish;\n}\nexport interface BaseInitializedEventEmittedResponse {\n  name: string;\n  symbol: string;\n  timestamp: BigNumberish;\n}\nexport interface BlockedEventEmittedResponse {\n  byProfileId: BigNumberish;\n  idOfProfileBlocked: BigNumberish;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface CollectNFTDeployedEventEmittedResponse {\n  profileId: BigNumberish;\n  pubId: BigNumberish;\n  collectNFT: string;\n  timestamp: BigNumberish;\n}\nexport interface CollectNFTTransferredEventEmittedResponse {\n  profileId: BigNumberish;\n  pubId: BigNumberish;\n  collectNFTId: BigNumberish;\n  from: string;\n  to: string;\n  timestamp: BigNumberish;\n}\nexport interface CollectedEventEmittedResponse {\n  collectedProfileId: BigNumberish;\n  collectedPubId: BigNumberish;\n  collectorProfileId: BigNumberish;\n  nftRecipient: string;\n  collectActionData: Arrayish;\n  collectActionResult: Arrayish;\n  collectNFT: string;\n  tokenId: BigNumberish;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface CommentParamsEventEmittedResponse {\n  profileId: BigNumberish;\n  contentURI: string;\n  pointedProfileId: BigNumberish;\n  pointedPubId: BigNumberish;\n  referrerProfileIds: BigNumberish[];\n  referrerPubIds: BigNumberish[];\n  referenceModuleData: Arrayish;\n  actionModules: string[];\n  actionModulesInitDatas: Arrayish[];\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n}\nexport interface CommentCreatedEventEmittedResponse {\n  commentParams: CommentParamsEventEmittedResponse;\n  pubId: BigNumberish;\n  referenceModuleReturnData: Arrayish;\n  actionModulesInitReturnDatas: Arrayish[];\n  referenceModuleInitReturnData: Arrayish;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface DelegatedExecutorsConfigAppliedEventEmittedResponse {\n  delegatorProfileId: BigNumberish;\n  configNumber: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface DelegatedExecutorsConfigChangedEventEmittedResponse {\n  delegatorProfileId: BigNumberish;\n  configNumber: BigNumberish;\n  delegatedExecutors: string[];\n  approvals: boolean[];\n  timestamp: BigNumberish;\n}\nexport interface EmergencyAdminSetEventEmittedResponse {\n  caller: string;\n  oldEmergencyAdmin: string;\n  newEmergencyAdmin: string;\n  timestamp: BigNumberish;\n}\nexport interface FollowModuleSetEventEmittedResponse {\n  profileId: BigNumberish;\n  followModule: string;\n  followModuleInitData: Arrayish;\n  followModuleReturnData: Arrayish;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface FollowModuleWhitelistedEventEmittedResponse {\n  followModule: string;\n  whitelisted: boolean;\n  timestamp: BigNumberish;\n}\nexport interface FollowNFTDeployedEventEmittedResponse {\n  profileId: BigNumberish;\n  followNFT: string;\n  timestamp: BigNumberish;\n}\nexport interface FollowedEventEmittedResponse {\n  followerProfileId: BigNumberish;\n  idOfProfileFollowed: BigNumberish;\n  followTokenIdAssigned: BigNumberish;\n  followModuleData: Arrayish;\n  processFollowModuleReturnData: Arrayish;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface GovernanceSetEventEmittedResponse {\n  caller: string;\n  prevGovernance: string;\n  newGovernance: string;\n  timestamp: BigNumberish;\n}\nexport interface MirrorParamsEventEmittedResponse {\n  profileId: BigNumberish;\n  metadataURI: string;\n  pointedProfileId: BigNumberish;\n  pointedPubId: BigNumberish;\n  referrerProfileIds: BigNumberish[];\n  referrerPubIds: BigNumberish[];\n  referenceModuleData: Arrayish;\n}\nexport interface MirrorCreatedEventEmittedResponse {\n  mirrorParams: MirrorParamsEventEmittedResponse;\n  pubId: BigNumberish;\n  referenceModuleReturnData: Arrayish;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface ModuleGlobalsCurrencyWhitelistedEventEmittedResponse {\n  currency: string;\n  prevWhitelisted: boolean;\n  whitelisted: boolean;\n  timestamp: BigNumberish;\n}\nexport interface ModuleGlobalsGovernanceSetEventEmittedResponse {\n  prevGovernance: string;\n  newGovernance: string;\n  timestamp: BigNumberish;\n}\nexport interface ModuleGlobalsTreasuryFeeSetEventEmittedResponse {\n  prevTreasuryFee: BigNumberish;\n  newTreasuryFee: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface ModuleGlobalsTreasurySetEventEmittedResponse {\n  prevTreasury: string;\n  newTreasury: string;\n  timestamp: BigNumberish;\n}\nexport interface PostParamsEventEmittedResponse {\n  profileId: BigNumberish;\n  contentURI: string;\n  actionModules: string[];\n  actionModulesInitDatas: Arrayish[];\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n}\nexport interface PostCreatedEventEmittedResponse {\n  postParams: PostParamsEventEmittedResponse;\n  pubId: BigNumberish;\n  actionModulesInitReturnDatas: Arrayish[];\n  referenceModuleInitReturnData: Arrayish;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface ProfileCreatedEventEmittedResponse {\n  profileId: BigNumberish;\n  creator: string;\n  to: string;\n  timestamp: BigNumberish;\n}\nexport interface ProfileCreatorWhitelistedEventEmittedResponse {\n  profileCreator: string;\n  whitelisted: boolean;\n  timestamp: BigNumberish;\n}\nexport interface ProfileMetadataSetEventEmittedResponse {\n  profileId: BigNumberish;\n  metadata: string;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface QuoteParamsEventEmittedResponse {\n  profileId: BigNumberish;\n  contentURI: string;\n  pointedProfileId: BigNumberish;\n  pointedPubId: BigNumberish;\n  referrerProfileIds: BigNumberish[];\n  referrerPubIds: BigNumberish[];\n  referenceModuleData: Arrayish;\n  actionModules: string[];\n  actionModulesInitDatas: Arrayish[];\n  referenceModule: string;\n  referenceModuleInitData: Arrayish;\n}\nexport interface QuoteCreatedEventEmittedResponse {\n  quoteParams: QuoteParamsEventEmittedResponse;\n  pubId: BigNumberish;\n  referenceModuleReturnData: Arrayish;\n  actionModulesInitReturnDatas: Arrayish[];\n  referenceModuleInitReturnData: Arrayish;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface ReferenceModuleWhitelistedEventEmittedResponse {\n  referenceModule: string;\n  whitelisted: boolean;\n  timestamp: BigNumberish;\n}\nexport interface StateSetEventEmittedResponse {\n  caller: string;\n  prevState: BigNumberish;\n  newState: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface TokenGuardianStateChangedEventEmittedResponse {\n  wallet: string;\n  enabled: boolean;\n  tokenGuardianDisablingTimestamp: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface UnblockedEventEmittedResponse {\n  byProfileId: BigNumberish;\n  idOfProfileUnblocked: BigNumberish;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface UnfollowedEventEmittedResponse {\n  unfollowerProfileId: BigNumberish;\n  idOfProfileUnfollowed: BigNumberish;\n  transactionExecutor: string;\n  timestamp: BigNumberish;\n}\nexport interface NonceUpdatedEventEmittedResponse {\n  signer: string;\n  nonce: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface LensUpgradeVersionEventEmittedResponse {\n  implementation: string;\n  version: string;\n  gitCommit: Arrayish;\n  timestamp: BigNumberish;\n}\nexport interface CollectedLegacyEventEmittedResponse {\n  publicationCollectedProfileId: BigNumberish;\n  publicationCollectedId: BigNumberish;\n  collectorProfileId: BigNumberish;\n  transactionExecutor: string;\n  referrerProfileId: BigNumberish;\n  referrerPubId: BigNumberish;\n  collectModule: string;\n  collectModuleData: Arrayish;\n  tokenId: BigNumberish;\n  timestamp: BigNumberish;\n}\nexport interface LensHubEvents {}\n"
  },
  {
    "path": "momoka-node/src/evm/anvil.ts",
    "content": "import { BigNumber } from 'ethers';\nimport { consoleLogWithLensNodeFootprint } from '../common/logger';\nimport { JSONRPCWithTimeout } from '../input-output/json-rpc-with-timeout';\nimport { EthereumNode } from './ethereum';\nimport { JSONRPCMethods } from './jsonrpc-methods';\n\n// eslint-disable-next-line @typescript-eslint/explicit-function-return-type\nconst execWrapper = async (command: string, callback: Function) => {\n  const { exec } = await import('child_process');\n  const childProcess = exec(command, { maxBuffer: Infinity });\n  return callback(childProcess);\n};\n\nconst mypromisify =\n  (fn: Function) =>\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  (...args: any) =>\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    new Promise((resolve) => fn(...args, (...a: any) => resolve(a)));\n\nconst execAsync = mypromisify(execWrapper);\n\nexport const LOCAL_NODE_URL = 'http://127.0.0.1:8545/';\n\nlet _cached_anvil_current_block_number: number | undefined = undefined;\nconst setAnvilCurrentBlockNumber = (blockNumber: number): void => {\n  _cached_anvil_current_block_number = blockNumber;\n};\n\n/**\n *  Get anvil node current block number\n */\nexport const getAnvilCurrentBlockNumber = async (): Promise<number> => {\n  if (_cached_anvil_current_block_number) {\n    return _cached_anvil_current_block_number;\n  }\n\n  const result = await JSONRPCWithTimeout<{ number: string }>(\n    LOCAL_NODE_URL,\n    JSONRPCMethods.eth_getBlockByNumber,\n    ['latest', false]\n  );\n\n  const blockNumber = BigNumber.from(result.number).toNumber();\n  setAnvilCurrentBlockNumber(blockNumber);\n\n  return blockNumber;\n};\n\n/**\n * Checks if the anvil node is alive aka up and running\n * @returns true if the anvil node is alive\n */\nconst isAnvilNodeAlive = async (): Promise<boolean> => {\n  try {\n    // will throw if not up\n    await getAnvilCurrentBlockNumber();\n  } catch (e) {\n    return false;\n  }\n\n  return true;\n};\n\nconst shutdownAnvilNode = async (): Promise<void> => {\n  await execAsync('lsof -t -i tcp:8545 | xargs kill');\n};\n\nconst closeEventsListeners = (): void => {\n  //do something when app is closing\n  process.on('exit', shutdownAnvilNode);\n\n  //catches ctrl+c event\n  process.on('SIGINT', shutdownAnvilNode);\n\n  // catches \"kill pid\" (for example: nodemon restart)\n  process.on('SIGUSR1', shutdownAnvilNode);\n  process.on('SIGUSR2', shutdownAnvilNode);\n};\n\nlet public_node_url: string | undefined;\n\n/**\n *  Sets up the local node from the fork\n * @param nodeUrl the node url to fork from\n */\nexport const setupAnvilLocalNode = async (nodeUrl: string): Promise<void> => {\n  public_node_url = nodeUrl;\n  consoleLogWithLensNodeFootprint('setting up anvil local node from the fork...');\n\n  if (await isAnvilNodeAlive()) {\n    consoleLogWithLensNodeFootprint('local node is already up, skipping setup...');\n    return;\n  }\n\n  consoleLogWithLensNodeFootprint('downloading foundry...');\n  await execAsync('curl -L https://foundry.paradigm.xyz | bash');\n  consoleLogWithLensNodeFootprint('downloaded foundry...');\n\n  consoleLogWithLensNodeFootprint('foundryup...');\n  await execAsync('foundryup');\n  consoleLogWithLensNodeFootprint('foundryup complete...');\n\n  // eslint-disable-next-line no-async-promise-executor\n  await new Promise<void>(async (resolve, _reject) => {\n    const internal = setInterval(async () => {\n      consoleLogWithLensNodeFootprint('checking local node status...');\n      if (await isAnvilNodeAlive()) {\n        consoleLogWithLensNodeFootprint('local node status.. ALIVE');\n        clearInterval(internal);\n        return resolve();\n      }\n\n      consoleLogWithLensNodeFootprint('local node status... STARTING');\n    }, 100);\n\n    consoleLogWithLensNodeFootprint('starting up anvil local node from the fork...');\n    await execAsync(\n      `REQ_TIMEOUT=100000 anvil --fork-url ${nodeUrl} --silent --timeout 1500 --retries 2`\n    );\n  });\n\n  closeEventsListeners();\n\n  consoleLogWithLensNodeFootprint('complete setup of anvil local node from fork...');\n};\n\n/**\n *  Reforks the local node from the archive node new block number\n * @param ethereumNode The ethereum node\n * @param blockNumber The block number to refork from\n */\nexport const anvilForkFrom = async (\n  ethereumNode: EthereumNode,\n  blockNumber: number\n): Promise<void> => {\n  if (!public_node_url) {\n    throw new Error('must call setupAnvilLocalNode before you can refork');\n  }\n  // Reset the fork node to the latest block.\n  await JSONRPCWithTimeout<void>(ethereumNode.nodeUrl, JSONRPCMethods.anvil_reset, [\n    {\n      forking: {\n        jsonRpcUrl: public_node_url,\n        blockNumber,\n      },\n    },\n  ]);\n\n  setAnvilCurrentBlockNumber(blockNumber);\n};\n"
  },
  {
    "path": "momoka-node/src/evm/contract-lens/lens-hub-v1-contract-abi.ts",
    "content": "export const LENS_HUB_V1_ABI = [\n  {\n    inputs: [\n      { internalType: 'address', name: 'followNFTImpl', type: 'address' },\n      { internalType: 'address', name: 'collectNFTImpl', type: 'address' },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'constructor',\n  },\n  { inputs: [], name: 'CallerNotCollectNFT', type: 'error' },\n  { inputs: [], name: 'CallerNotFollowNFT', type: 'error' },\n  { inputs: [], name: 'CannotInitImplementation', type: 'error' },\n  { inputs: [], name: 'DispatcherNotSet', type: 'error' },\n  { inputs: [], name: 'EmergencyAdminCannotUnpause', type: 'error' },\n  { inputs: [], name: 'InitParamsInvalid', type: 'error' },\n  { inputs: [], name: 'Initialized', type: 'error' },\n  { inputs: [], name: 'NotGovernance', type: 'error' },\n  { inputs: [], name: 'NotGovernanceOrEmergencyAdmin', type: 'error' },\n  { inputs: [], name: 'NotOwnerOrApproved', type: 'error' },\n  { inputs: [], name: 'NotProfileOwner', type: 'error' },\n  { inputs: [], name: 'NotProfileOwnerOrDispatcher', type: 'error' },\n  { inputs: [], name: 'Paused', type: 'error' },\n  { inputs: [], name: 'ProfileCreatorNotWhitelisted', type: 'error' },\n  { inputs: [], name: 'ProfileImageURILengthInvalid', type: 'error' },\n  { inputs: [], name: 'PublicationDoesNotExist', type: 'error' },\n  { inputs: [], name: 'PublishingPaused', type: 'error' },\n  { inputs: [], name: 'SignatureExpired', type: 'error' },\n  { inputs: [], name: 'SignatureInvalid', type: 'error' },\n  { inputs: [], name: 'ZeroSpender', type: 'error' },\n  {\n    anonymous: false,\n    inputs: [\n      { indexed: true, internalType: 'address', name: 'owner', type: 'address' },\n      { indexed: true, internalType: 'address', name: 'approved', type: 'address' },\n      { indexed: true, internalType: 'uint256', name: 'tokenId', type: 'uint256' },\n    ],\n    name: 'Approval',\n    type: 'event',\n  },\n  {\n    anonymous: false,\n    inputs: [\n      { indexed: true, internalType: 'address', name: 'owner', type: 'address' },\n      { indexed: true, internalType: 'address', name: 'operator', type: 'address' },\n      { indexed: false, internalType: 'bool', name: 'approved', type: 'bool' },\n    ],\n    name: 'ApprovalForAll',\n    type: 'event',\n  },\n  {\n    anonymous: false,\n    inputs: [\n      { indexed: true, internalType: 'address', name: 'from', type: 'address' },\n      { indexed: true, internalType: 'address', name: 'to', type: 'address' },\n      { indexed: true, internalType: 'uint256', name: 'tokenId', type: 'uint256' },\n    ],\n    name: 'Transfer',\n    type: 'event',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'to', type: 'address' },\n      { internalType: 'uint256', name: 'tokenId', type: 'uint256' },\n    ],\n    name: 'approve',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'address', name: 'owner', type: 'address' }],\n    name: 'balanceOf',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }],\n    name: 'burn',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'tokenId', type: 'uint256' },\n      {\n        components: [\n          { internalType: 'uint8', name: 'v', type: 'uint8' },\n          { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n          { internalType: 'bytes32', name: 's', type: 'bytes32' },\n          { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n        ],\n        internalType: 'struct DataTypes.EIP712Signature',\n        name: 'sig',\n        type: 'tuple',\n      },\n    ],\n    name: 'burnWithSig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'uint256', name: 'pubId', type: 'uint256' },\n      { internalType: 'bytes', name: 'data', type: 'bytes' },\n    ],\n    name: 'collect',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'address', name: 'collector', type: 'address' },\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'uint256', name: 'pubId', type: 'uint256' },\n          { internalType: 'bytes', name: 'data', type: 'bytes' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.CollectWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'collectWithSig',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'string', name: 'contentURI', type: 'string' },\n          { internalType: 'uint256', name: 'profileIdPointed', type: 'uint256' },\n          { internalType: 'uint256', name: 'pubIdPointed', type: 'uint256' },\n          { internalType: 'bytes', name: 'referenceModuleData', type: 'bytes' },\n          { internalType: 'address', name: 'collectModule', type: 'address' },\n          { internalType: 'bytes', name: 'collectModuleInitData', type: 'bytes' },\n          { internalType: 'address', name: 'referenceModule', type: 'address' },\n          { internalType: 'bytes', name: 'referenceModuleInitData', type: 'bytes' },\n        ],\n        internalType: 'struct DataTypes.CommentData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'comment',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'string', name: 'contentURI', type: 'string' },\n          { internalType: 'uint256', name: 'profileIdPointed', type: 'uint256' },\n          { internalType: 'uint256', name: 'pubIdPointed', type: 'uint256' },\n          { internalType: 'bytes', name: 'referenceModuleData', type: 'bytes' },\n          { internalType: 'address', name: 'collectModule', type: 'address' },\n          { internalType: 'bytes', name: 'collectModuleInitData', type: 'bytes' },\n          { internalType: 'address', name: 'referenceModule', type: 'address' },\n          { internalType: 'bytes', name: 'referenceModuleInitData', type: 'bytes' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.CommentWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'commentWithSig',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'string', name: 'contentURI', type: 'string' },\n          { internalType: 'uint256', name: 'profileIdPointed', type: 'uint256' },\n          { internalType: 'uint256', name: 'pubIdPointed', type: 'uint256' },\n          { internalType: 'bytes', name: 'referenceModuleData', type: 'bytes' },\n          { internalType: 'address', name: 'collectModule', type: 'address' },\n          { internalType: 'bytes', name: 'collectModuleInitData', type: 'bytes' },\n          { internalType: 'address', name: 'referenceModule', type: 'address' },\n          { internalType: 'bytes', name: 'referenceModuleInitData', type: 'bytes' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.CommentWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'commentWithSig_Dispatcher',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'address', name: 'to', type: 'address' },\n          { internalType: 'string', name: 'handle', type: 'string' },\n          { internalType: 'string', name: 'imageURI', type: 'string' },\n          { internalType: 'address', name: 'followModule', type: 'address' },\n          { internalType: 'bytes', name: 'followModuleInitData', type: 'bytes' },\n          { internalType: 'string', name: 'followNFTURI', type: 'string' },\n        ],\n        internalType: 'struct DataTypes.CreateProfileData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'createProfile',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'address', name: 'wallet', type: 'address' }],\n    name: 'defaultProfile',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'uint256', name: 'pubId', type: 'uint256' },\n      { internalType: 'uint256', name: 'collectNFTId', type: 'uint256' },\n      { internalType: 'address', name: 'from', type: 'address' },\n      { internalType: 'address', name: 'to', type: 'address' },\n    ],\n    name: 'emitCollectNFTTransferEvent',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'uint256', name: 'followNFTId', type: 'uint256' },\n      { internalType: 'address', name: 'from', type: 'address' },\n      { internalType: 'address', name: 'to', type: 'address' },\n    ],\n    name: 'emitFollowNFTTransferEvent',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }],\n    name: 'exists',\n    outputs: [{ internalType: 'bool', name: '', type: 'bool' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256[]', name: 'profileIds', type: 'uint256[]' },\n      { internalType: 'bytes[]', name: 'datas', type: 'bytes[]' },\n    ],\n    name: 'follow',\n    outputs: [{ internalType: 'uint256[]', name: '', type: 'uint256[]' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'address', name: 'follower', type: 'address' },\n          { internalType: 'uint256[]', name: 'profileIds', type: 'uint256[]' },\n          { internalType: 'bytes[]', name: 'datas', type: 'bytes[]' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.FollowWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'followWithSig',\n    outputs: [{ internalType: 'uint256[]', name: '', type: 'uint256[]' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }],\n    name: 'getApproved',\n    outputs: [{ internalType: 'address', name: '', type: 'address' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'uint256', name: 'pubId', type: 'uint256' },\n    ],\n    name: 'getCollectModule',\n    outputs: [{ internalType: 'address', name: '', type: 'address' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'uint256', name: 'pubId', type: 'uint256' },\n    ],\n    name: 'getCollectNFT',\n    outputs: [{ internalType: 'address', name: '', type: 'address' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getCollectNFTImpl',\n    outputs: [{ internalType: 'address', name: '', type: 'address' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'uint256', name: 'pubId', type: 'uint256' },\n    ],\n    name: 'getContentURI',\n    outputs: [{ internalType: 'string', name: '', type: 'string' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'profileId', type: 'uint256' }],\n    name: 'getDispatcher',\n    outputs: [{ internalType: 'address', name: '', type: 'address' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getDomainSeparator',\n    outputs: [{ internalType: 'bytes32', name: '', type: 'bytes32' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'profileId', type: 'uint256' }],\n    name: 'getFollowModule',\n    outputs: [{ internalType: 'address', name: '', type: 'address' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'profileId', type: 'uint256' }],\n    name: 'getFollowNFT',\n    outputs: [{ internalType: 'address', name: '', type: 'address' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getFollowNFTImpl',\n    outputs: [{ internalType: 'address', name: '', type: 'address' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'profileId', type: 'uint256' }],\n    name: 'getFollowNFTURI',\n    outputs: [{ internalType: 'string', name: '', type: 'string' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getGovernance',\n    outputs: [{ internalType: 'address', name: '', type: 'address' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'profileId', type: 'uint256' }],\n    name: 'getHandle',\n    outputs: [{ internalType: 'string', name: '', type: 'string' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'profileId', type: 'uint256' }],\n    name: 'getProfile',\n    outputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'pubCount', type: 'uint256' },\n          { internalType: 'address', name: 'followModule', type: 'address' },\n          { internalType: 'address', name: 'followNFT', type: 'address' },\n          { internalType: 'string', name: 'handle', type: 'string' },\n          { internalType: 'string', name: 'imageURI', type: 'string' },\n          { internalType: 'string', name: 'followNFTURI', type: 'string' },\n        ],\n        internalType: 'struct DataTypes.ProfileStruct',\n        name: '',\n        type: 'tuple',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'string', name: 'handle', type: 'string' }],\n    name: 'getProfileIdByHandle',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'uint256', name: 'pubId', type: 'uint256' },\n    ],\n    name: 'getPub',\n    outputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileIdPointed', type: 'uint256' },\n          { internalType: 'uint256', name: 'pubIdPointed', type: 'uint256' },\n          { internalType: 'string', name: 'contentURI', type: 'string' },\n          { internalType: 'address', name: 'referenceModule', type: 'address' },\n          { internalType: 'address', name: 'collectModule', type: 'address' },\n          { internalType: 'address', name: 'collectNFT', type: 'address' },\n        ],\n        internalType: 'struct DataTypes.PublicationStruct',\n        name: '',\n        type: 'tuple',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'profileId', type: 'uint256' }],\n    name: 'getPubCount',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'uint256', name: 'pubId', type: 'uint256' },\n    ],\n    name: 'getPubPointer',\n    outputs: [\n      { internalType: 'uint256', name: '', type: 'uint256' },\n      { internalType: 'uint256', name: '', type: 'uint256' },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'uint256', name: 'pubId', type: 'uint256' },\n    ],\n    name: 'getPubType',\n    outputs: [{ internalType: 'enum DataTypes.PubType', name: '', type: 'uint8' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'uint256', name: 'pubId', type: 'uint256' },\n    ],\n    name: 'getReferenceModule',\n    outputs: [{ internalType: 'address', name: '', type: 'address' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getState',\n    outputs: [{ internalType: 'enum DataTypes.ProtocolState', name: '', type: 'uint8' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'string', name: 'name', type: 'string' },\n      { internalType: 'string', name: 'symbol', type: 'string' },\n      { internalType: 'address', name: 'newGovernance', type: 'address' },\n    ],\n    name: 'initialize',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'owner', type: 'address' },\n      { internalType: 'address', name: 'operator', type: 'address' },\n    ],\n    name: 'isApprovedForAll',\n    outputs: [{ internalType: 'bool', name: '', type: 'bool' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'address', name: 'collectModule', type: 'address' }],\n    name: 'isCollectModuleWhitelisted',\n    outputs: [{ internalType: 'bool', name: '', type: 'bool' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'address', name: 'followModule', type: 'address' }],\n    name: 'isFollowModuleWhitelisted',\n    outputs: [{ internalType: 'bool', name: '', type: 'bool' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'address', name: 'profileCreator', type: 'address' }],\n    name: 'isProfileCreatorWhitelisted',\n    outputs: [{ internalType: 'bool', name: '', type: 'bool' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'address', name: 'referenceModule', type: 'address' }],\n    name: 'isReferenceModuleWhitelisted',\n    outputs: [{ internalType: 'bool', name: '', type: 'bool' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }],\n    name: 'mintTimestampOf',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'uint256', name: 'profileIdPointed', type: 'uint256' },\n          { internalType: 'uint256', name: 'pubIdPointed', type: 'uint256' },\n          { internalType: 'bytes', name: 'referenceModuleData', type: 'bytes' },\n          { internalType: 'address', name: 'referenceModule', type: 'address' },\n          { internalType: 'bytes', name: 'referenceModuleInitData', type: 'bytes' },\n        ],\n        internalType: 'struct DataTypes.MirrorData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'mirror',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'uint256', name: 'profileIdPointed', type: 'uint256' },\n          { internalType: 'uint256', name: 'pubIdPointed', type: 'uint256' },\n          { internalType: 'bytes', name: 'referenceModuleData', type: 'bytes' },\n          { internalType: 'address', name: 'referenceModule', type: 'address' },\n          { internalType: 'bytes', name: 'referenceModuleInitData', type: 'bytes' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.MirrorWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'mirrorWithSig',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'uint256', name: 'profileIdPointed', type: 'uint256' },\n          { internalType: 'uint256', name: 'pubIdPointed', type: 'uint256' },\n          { internalType: 'bytes', name: 'referenceModuleData', type: 'bytes' },\n          { internalType: 'address', name: 'referenceModule', type: 'address' },\n          { internalType: 'bytes', name: 'referenceModuleInitData', type: 'bytes' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.MirrorWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'mirrorWithSig_Dispatcher',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'name',\n    outputs: [{ internalType: 'string', name: '', type: 'string' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }],\n    name: 'ownerOf',\n    outputs: [{ internalType: 'address', name: '', type: 'address' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'spender', type: 'address' },\n      { internalType: 'uint256', name: 'tokenId', type: 'uint256' },\n      {\n        components: [\n          { internalType: 'uint8', name: 'v', type: 'uint8' },\n          { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n          { internalType: 'bytes32', name: 's', type: 'bytes32' },\n          { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n        ],\n        internalType: 'struct DataTypes.EIP712Signature',\n        name: 'sig',\n        type: 'tuple',\n      },\n    ],\n    name: 'permit',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'owner', type: 'address' },\n      { internalType: 'address', name: 'operator', type: 'address' },\n      { internalType: 'bool', name: 'approved', type: 'bool' },\n      {\n        components: [\n          { internalType: 'uint8', name: 'v', type: 'uint8' },\n          { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n          { internalType: 'bytes32', name: 's', type: 'bytes32' },\n          { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n        ],\n        internalType: 'struct DataTypes.EIP712Signature',\n        name: 'sig',\n        type: 'tuple',\n      },\n    ],\n    name: 'permitForAll',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'string', name: 'contentURI', type: 'string' },\n          { internalType: 'address', name: 'collectModule', type: 'address' },\n          { internalType: 'bytes', name: 'collectModuleInitData', type: 'bytes' },\n          { internalType: 'address', name: 'referenceModule', type: 'address' },\n          { internalType: 'bytes', name: 'referenceModuleInitData', type: 'bytes' },\n        ],\n        internalType: 'struct DataTypes.PostData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'post',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'string', name: 'contentURI', type: 'string' },\n          { internalType: 'address', name: 'collectModule', type: 'address' },\n          { internalType: 'bytes', name: 'collectModuleInitData', type: 'bytes' },\n          { internalType: 'address', name: 'referenceModule', type: 'address' },\n          { internalType: 'bytes', name: 'referenceModuleInitData', type: 'bytes' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.PostWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'postWithSig',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'string', name: 'contentURI', type: 'string' },\n          { internalType: 'address', name: 'collectModule', type: 'address' },\n          { internalType: 'bytes', name: 'collectModuleInitData', type: 'bytes' },\n          { internalType: 'address', name: 'referenceModule', type: 'address' },\n          { internalType: 'bytes', name: 'referenceModuleInitData', type: 'bytes' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.PostWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'postWithSig_Dispatcher',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'from', type: 'address' },\n      { internalType: 'address', name: 'to', type: 'address' },\n      { internalType: 'uint256', name: 'tokenId', type: 'uint256' },\n    ],\n    name: 'safeTransferFrom',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'from', type: 'address' },\n      { internalType: 'address', name: 'to', type: 'address' },\n      { internalType: 'uint256', name: 'tokenId', type: 'uint256' },\n      { internalType: 'bytes', name: '_data', type: 'bytes' },\n    ],\n    name: 'safeTransferFrom',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'operator', type: 'address' },\n      { internalType: 'bool', name: 'approved', type: 'bool' },\n    ],\n    name: 'setApprovalForAll',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'profileId', type: 'uint256' }],\n    name: 'setDefaultProfile',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'address', name: 'wallet', type: 'address' },\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.SetDefaultProfileWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'setDefaultProfileWithSig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'address', name: 'dispatcher', type: 'address' },\n    ],\n    name: 'setDispatcher',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'address', name: 'dispatcher', type: 'address' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.SetDispatcherWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'setDispatcherWithSig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'address', name: 'newEmergencyAdmin', type: 'address' }],\n    name: 'setEmergencyAdmin',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'address', name: 'followModule', type: 'address' },\n      { internalType: 'bytes', name: 'followModuleInitData', type: 'bytes' },\n    ],\n    name: 'setFollowModule',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'address', name: 'followModule', type: 'address' },\n          { internalType: 'bytes', name: 'followModuleInitData', type: 'bytes' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.SetFollowModuleWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'setFollowModuleWithSig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'string', name: 'followNFTURI', type: 'string' },\n    ],\n    name: 'setFollowNFTURI',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'string', name: 'followNFTURI', type: 'string' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.SetFollowNFTURIWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'setFollowNFTURIWithSig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'address', name: 'newGovernance', type: 'address' }],\n    name: 'setGovernance',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n      { internalType: 'string', name: 'imageURI', type: 'string' },\n    ],\n    name: 'setProfileImageURI',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          { internalType: 'uint256', name: 'profileId', type: 'uint256' },\n          { internalType: 'string', name: 'imageURI', type: 'string' },\n          {\n            components: [\n              { internalType: 'uint8', name: 'v', type: 'uint8' },\n              { internalType: 'bytes32', name: 'r', type: 'bytes32' },\n              { internalType: 'bytes32', name: 's', type: 'bytes32' },\n              { internalType: 'uint256', name: 'deadline', type: 'uint256' },\n            ],\n            internalType: 'struct DataTypes.EIP712Signature',\n            name: 'sig',\n            type: 'tuple',\n          },\n        ],\n        internalType: 'struct DataTypes.SetProfileImageURIWithSigData',\n        name: 'vars',\n        type: 'tuple',\n      },\n    ],\n    name: 'setProfileImageURIWithSig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'enum DataTypes.ProtocolState', name: 'newState', type: 'uint8' }],\n    name: 'setState',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'address', name: '', type: 'address' }],\n    name: 'sigNonces',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'bytes4', name: 'interfaceId', type: 'bytes4' }],\n    name: 'supportsInterface',\n    outputs: [{ internalType: 'bool', name: '', type: 'bool' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'symbol',\n    outputs: [{ internalType: 'string', name: '', type: 'string' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'index', type: 'uint256' }],\n    name: 'tokenByIndex',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }],\n    name: 'tokenDataOf',\n    outputs: [\n      {\n        components: [\n          { internalType: 'address', name: 'owner', type: 'address' },\n          { internalType: 'uint96', name: 'mintTimestamp', type: 'uint96' },\n        ],\n        internalType: 'struct IERC721Time.TokenData',\n        name: '',\n        type: 'tuple',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'owner', type: 'address' },\n      { internalType: 'uint256', name: 'index', type: 'uint256' },\n    ],\n    name: 'tokenOfOwnerByIndex',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [{ internalType: 'uint256', name: 'tokenId', type: 'uint256' }],\n    name: 'tokenURI',\n    outputs: [{ internalType: 'string', name: '', type: 'string' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'totalSupply',\n    outputs: [{ internalType: 'uint256', name: '', type: 'uint256' }],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'from', type: 'address' },\n      { internalType: 'address', name: 'to', type: 'address' },\n      { internalType: 'uint256', name: 'tokenId', type: 'uint256' },\n    ],\n    name: 'transferFrom',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'collectModule', type: 'address' },\n      { internalType: 'bool', name: 'whitelist', type: 'bool' },\n    ],\n    name: 'whitelistCollectModule',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'followModule', type: 'address' },\n      { internalType: 'bool', name: 'whitelist', type: 'bool' },\n    ],\n    name: 'whitelistFollowModule',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'profileCreator', type: 'address' },\n      { internalType: 'bool', name: 'whitelist', type: 'bool' },\n    ],\n    name: 'whitelistProfileCreator',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      { internalType: 'address', name: 'referenceModule', type: 'address' },\n      { internalType: 'bool', name: 'whitelist', type: 'bool' },\n    ],\n    name: 'whitelistReferenceModule',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n];\n"
  },
  {
    "path": "momoka-node/src/evm/contract-lens/lens-hub-v2-contract-abi.ts",
    "content": "export const LENS_HUB_V2_ABI = [\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'followNFTImpl',\n        type: 'address',\n      },\n      {\n        internalType: 'address',\n        name: 'collectNFTImpl',\n        type: 'address',\n      },\n      {\n        internalType: 'address',\n        name: 'moduleRegistry',\n        type: 'address',\n      },\n      {\n        internalType: 'uint256',\n        name: 'tokenGuardianCooldown',\n        type: 'uint256',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'lensHandlesAddress',\n            type: 'address',\n          },\n          {\n            internalType: 'address',\n            name: 'tokenHandleRegistryAddress',\n            type: 'address',\n          },\n          {\n            internalType: 'address',\n            name: 'legacyFeeFollowModule',\n            type: 'address',\n          },\n          {\n            internalType: 'address',\n            name: 'legacyProfileFollowModule',\n            type: 'address',\n          },\n          {\n            internalType: 'address',\n            name: 'newFeeFollowModule',\n            type: 'address',\n          },\n          {\n            internalType: 'address',\n            name: 'migrationAdmin',\n            type: 'address',\n          },\n        ],\n        internalType: 'struct Types.MigrationParams',\n        name: 'migrationParams',\n        type: 'tuple',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'constructor',\n  },\n  {\n    inputs: [],\n    name: 'AlreadyEnabled',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'CallerNotCollectNFT',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'CallerNotFollowNFT',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'CannotInitImplementation',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'DisablingAlreadyTriggered',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'ExecutorInvalid',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'GuardianEnabled',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'InitParamsInvalid',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'Initialized',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'InvalidOwner',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'InvalidParameter',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'NonERC721ReceiverImplementer',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'NotEOA',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'NotGovernance',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'NotMigrationAdmin',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'NotOwnerOrApproved',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'NotProfileOwner',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'NotWhitelisted',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'Paused',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'PublishingPaused',\n    type: 'error',\n  },\n  {\n    inputs: [],\n    name: 'TokenDoesNotExist',\n    type: 'error',\n  },\n  {\n    anonymous: false,\n    inputs: [\n      {\n        indexed: true,\n        internalType: 'address',\n        name: 'owner',\n        type: 'address',\n      },\n      {\n        indexed: true,\n        internalType: 'address',\n        name: 'approved',\n        type: 'address',\n      },\n      {\n        indexed: true,\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'Approval',\n    type: 'event',\n  },\n  {\n    anonymous: false,\n    inputs: [\n      {\n        indexed: true,\n        internalType: 'address',\n        name: 'owner',\n        type: 'address',\n      },\n      {\n        indexed: true,\n        internalType: 'address',\n        name: 'operator',\n        type: 'address',\n      },\n      {\n        indexed: false,\n        internalType: 'bool',\n        name: 'approved',\n        type: 'bool',\n      },\n    ],\n    name: 'ApprovalForAll',\n    type: 'event',\n  },\n  {\n    anonymous: false,\n    inputs: [\n      {\n        indexed: true,\n        internalType: 'address',\n        name: 'from',\n        type: 'address',\n      },\n      {\n        indexed: true,\n        internalType: 'address',\n        name: 'to',\n        type: 'address',\n      },\n      {\n        indexed: true,\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'Transfer',\n    type: 'event',\n  },\n  {\n    inputs: [],\n    name: 'DANGER__disableTokenGuardian',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'publicationActedProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'publicationActedId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'actorProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerProfileIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerPubIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'address',\n            name: 'actionModuleAddress',\n            type: 'address',\n          },\n          {\n            internalType: 'bytes',\n            name: 'actionModuleData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.PublicationActionParams',\n        name: 'publicationActionParams',\n        type: 'tuple',\n      },\n    ],\n    name: 'act',\n    outputs: [\n      {\n        internalType: 'bytes',\n        name: '',\n        type: 'bytes',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'publicationActedProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'publicationActedId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'actorProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerProfileIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerPubIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'address',\n            name: 'actionModuleAddress',\n            type: 'address',\n          },\n          {\n            internalType: 'bytes',\n            name: 'actionModuleData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.PublicationActionParams',\n        name: 'publicationActionParams',\n        type: 'tuple',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'actWithSig',\n    outputs: [\n      {\n        internalType: 'bytes',\n        name: '',\n        type: 'bytes',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'to',\n        type: 'address',\n      },\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'approve',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'owner',\n        type: 'address',\n      },\n    ],\n    name: 'balanceOf',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256[]',\n        name: 'profileIds',\n        type: 'uint256[]',\n      },\n    ],\n    name: 'batchMigrateFollowModules',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256[]',\n        name: 'followerProfileIds',\n        type: 'uint256[]',\n      },\n      {\n        internalType: 'uint256',\n        name: 'idOfProfileFollowed',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256[]',\n        name: 'followTokenIds',\n        type: 'uint256[]',\n      },\n    ],\n    name: 'batchMigrateFollowers',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'followerProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256[]',\n        name: 'idsOfProfileFollowed',\n        type: 'uint256[]',\n      },\n      {\n        internalType: 'uint256[]',\n        name: 'followTokenIds',\n        type: 'uint256[]',\n      },\n    ],\n    name: 'batchMigrateFollows',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256[]',\n        name: 'profileIds',\n        type: 'uint256[]',\n      },\n    ],\n    name: 'batchMigrateProfiles',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'burn',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'delegatorProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'address[]',\n        name: 'delegatedExecutors',\n        type: 'address[]',\n      },\n      {\n        internalType: 'bool[]',\n        name: 'approvals',\n        type: 'bool[]',\n      },\n      {\n        internalType: 'uint64',\n        name: 'configNumber',\n        type: 'uint64',\n      },\n      {\n        internalType: 'bool',\n        name: 'switchToGivenConfig',\n        type: 'bool',\n      },\n    ],\n    name: 'changeDelegatedExecutorsConfig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'delegatorProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'address[]',\n        name: 'delegatedExecutors',\n        type: 'address[]',\n      },\n      {\n        internalType: 'bool[]',\n        name: 'approvals',\n        type: 'bool[]',\n      },\n    ],\n    name: 'changeDelegatedExecutorsConfig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'delegatorProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'address[]',\n        name: 'delegatedExecutors',\n        type: 'address[]',\n      },\n      {\n        internalType: 'bool[]',\n        name: 'approvals',\n        type: 'bool[]',\n      },\n      {\n        internalType: 'uint64',\n        name: 'configNumber',\n        type: 'uint64',\n      },\n      {\n        internalType: 'bool',\n        name: 'switchToGivenConfig',\n        type: 'bool',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'changeDelegatedExecutorsConfigWithSig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'publicationCollectedProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'publicationCollectedId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'collectorProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'referrerProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'referrerPubId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'bytes',\n            name: 'collectModuleData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.LegacyCollectParams',\n        name: 'collectParams',\n        type: 'tuple',\n      },\n    ],\n    name: 'collectLegacy',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'publicationCollectedProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'publicationCollectedId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'collectorProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'referrerProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'referrerPubId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'bytes',\n            name: 'collectModuleData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.LegacyCollectParams',\n        name: 'collectParams',\n        type: 'tuple',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'collectLegacyWithSig',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'profileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'string',\n            name: 'contentURI',\n            type: 'string',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedPubId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerProfileIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerPubIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleData',\n            type: 'bytes',\n          },\n          {\n            internalType: 'address[]',\n            name: 'actionModules',\n            type: 'address[]',\n          },\n          {\n            internalType: 'bytes[]',\n            name: 'actionModulesInitDatas',\n            type: 'bytes[]',\n          },\n          {\n            internalType: 'address',\n            name: 'referenceModule',\n            type: 'address',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleInitData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.CommentParams',\n        name: 'commentParams',\n        type: 'tuple',\n      },\n    ],\n    name: 'comment',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'profileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'string',\n            name: 'contentURI',\n            type: 'string',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedPubId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerProfileIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerPubIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleData',\n            type: 'bytes',\n          },\n          {\n            internalType: 'address[]',\n            name: 'actionModules',\n            type: 'address[]',\n          },\n          {\n            internalType: 'bytes[]',\n            name: 'actionModulesInitDatas',\n            type: 'bytes[]',\n          },\n          {\n            internalType: 'address',\n            name: 'referenceModule',\n            type: 'address',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleInitData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.CommentParams',\n        name: 'commentParams',\n        type: 'tuple',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'commentWithSig',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'to',\n            type: 'address',\n          },\n          {\n            internalType: 'address',\n            name: 'followModule',\n            type: 'address',\n          },\n          {\n            internalType: 'bytes',\n            name: 'followModuleInitData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.CreateProfileParams',\n        name: 'createProfileParams',\n        type: 'tuple',\n      },\n    ],\n    name: 'createProfile',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'profileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256',\n        name: 'pubId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256',\n        name: 'collectNFTId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'address',\n        name: 'from',\n        type: 'address',\n      },\n      {\n        internalType: 'address',\n        name: 'to',\n        type: 'address',\n      },\n    ],\n    name: 'emitCollectNFTTransferEvent',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'unfollowerProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256',\n        name: 'idOfProfileUnfollowed',\n        type: 'uint256',\n      },\n      {\n        internalType: 'address',\n        name: 'transactionExecutor',\n        type: 'address',\n      },\n    ],\n    name: 'emitUnfollowedEvent',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'enableTokenGuardian',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'exists',\n    outputs: [\n      {\n        internalType: 'bool',\n        name: '',\n        type: 'bool',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'followerProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256[]',\n        name: 'idsOfProfilesToFollow',\n        type: 'uint256[]',\n      },\n      {\n        internalType: 'uint256[]',\n        name: 'followTokenIds',\n        type: 'uint256[]',\n      },\n      {\n        internalType: 'bytes[]',\n        name: 'datas',\n        type: 'bytes[]',\n      },\n    ],\n    name: 'follow',\n    outputs: [\n      {\n        internalType: 'uint256[]',\n        name: '',\n        type: 'uint256[]',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'followerProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256[]',\n        name: 'idsOfProfilesToFollow',\n        type: 'uint256[]',\n      },\n      {\n        internalType: 'uint256[]',\n        name: 'followTokenIds',\n        type: 'uint256[]',\n      },\n      {\n        internalType: 'bytes[]',\n        name: 'datas',\n        type: 'bytes[]',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'followWithSig',\n    outputs: [\n      {\n        internalType: 'uint256[]',\n        name: '',\n        type: 'uint256[]',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'getApproved',\n    outputs: [\n      {\n        internalType: 'address',\n        name: '',\n        type: 'address',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'profileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256',\n        name: 'pubId',\n        type: 'uint256',\n      },\n    ],\n    name: 'getContentURI',\n    outputs: [\n      {\n        internalType: 'string',\n        name: '',\n        type: 'string',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'delegatorProfileId',\n        type: 'uint256',\n      },\n    ],\n    name: 'getDelegatedExecutorsConfigNumber',\n    outputs: [\n      {\n        internalType: 'uint64',\n        name: '',\n        type: 'uint64',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'delegatorProfileId',\n        type: 'uint256',\n      },\n    ],\n    name: 'getDelegatedExecutorsMaxConfigNumberSet',\n    outputs: [\n      {\n        internalType: 'uint64',\n        name: '',\n        type: 'uint64',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'delegatorProfileId',\n        type: 'uint256',\n      },\n    ],\n    name: 'getDelegatedExecutorsPrevConfigNumber',\n    outputs: [\n      {\n        internalType: 'uint64',\n        name: '',\n        type: 'uint64',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getDomainSeparator',\n    outputs: [\n      {\n        internalType: 'bytes32',\n        name: '',\n        type: 'bytes32',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getFollowNFTImpl',\n    outputs: [\n      {\n        internalType: 'address',\n        name: '',\n        type: 'address',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getGovernance',\n    outputs: [\n      {\n        internalType: 'address',\n        name: '',\n        type: 'address',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getLegacyCollectNFTImpl',\n    outputs: [\n      {\n        internalType: 'address',\n        name: '',\n        type: 'address',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getModuleRegistry',\n    outputs: [\n      {\n        internalType: 'address',\n        name: '',\n        type: 'address',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'profileId',\n        type: 'uint256',\n      },\n    ],\n    name: 'getProfile',\n    outputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'pubCount',\n            type: 'uint256',\n          },\n          {\n            internalType: 'address',\n            name: 'followModule',\n            type: 'address',\n          },\n          {\n            internalType: 'address',\n            name: 'followNFT',\n            type: 'address',\n          },\n          {\n            internalType: 'string',\n            name: '__DEPRECATED__handle',\n            type: 'string',\n          },\n          {\n            internalType: 'string',\n            name: '__DEPRECATED__imageURI',\n            type: 'string',\n          },\n          {\n            internalType: 'string',\n            name: '__DEPRECATED__followNFTURI',\n            type: 'string',\n          },\n          {\n            internalType: 'string',\n            name: 'metadataURI',\n            type: 'string',\n          },\n        ],\n        internalType: 'struct Types.Profile',\n        name: '',\n        type: 'tuple',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'bytes32',\n        name: 'handleHash',\n        type: 'bytes32',\n      },\n    ],\n    name: 'getProfileIdByHandleHash',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'profileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256',\n        name: 'pubId',\n        type: 'uint256',\n      },\n    ],\n    name: 'getPublication',\n    outputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'pointedProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedPubId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'string',\n            name: 'contentURI',\n            type: 'string',\n          },\n          {\n            internalType: 'address',\n            name: 'referenceModule',\n            type: 'address',\n          },\n          {\n            internalType: 'address',\n            name: '__DEPRECATED__collectModule',\n            type: 'address',\n          },\n          {\n            internalType: 'address',\n            name: '__DEPRECATED__collectNFT',\n            type: 'address',\n          },\n          {\n            internalType: 'enum Types.PublicationType',\n            name: 'pubType',\n            type: 'uint8',\n          },\n          {\n            internalType: 'uint256',\n            name: 'rootProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'rootPubId',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.PublicationMemory',\n        name: '',\n        type: 'tuple',\n      },\n    ],\n    stateMutability: 'pure',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'profileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256',\n        name: 'pubId',\n        type: 'uint256',\n      },\n    ],\n    name: 'getPublicationType',\n    outputs: [\n      {\n        internalType: 'enum Types.PublicationType',\n        name: '',\n        type: 'uint8',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getState',\n    outputs: [\n      {\n        internalType: 'enum Types.ProtocolState',\n        name: '',\n        type: 'uint8',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'wallet',\n        type: 'address',\n      },\n    ],\n    name: 'getTokenGuardianDisablingTimestamp',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getTreasury',\n    outputs: [\n      {\n        internalType: 'address',\n        name: '',\n        type: 'address',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getTreasuryData',\n    outputs: [\n      {\n        internalType: 'address',\n        name: '',\n        type: 'address',\n      },\n      {\n        internalType: 'uint16',\n        name: '',\n        type: 'uint16',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'getTreasuryFee',\n    outputs: [\n      {\n        internalType: 'uint16',\n        name: '',\n        type: 'uint16',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'string',\n        name: 'name',\n        type: 'string',\n      },\n      {\n        internalType: 'string',\n        name: 'symbol',\n        type: 'string',\n      },\n      {\n        internalType: 'address',\n        name: 'newGovernance',\n        type: 'address',\n      },\n    ],\n    name: 'initialize',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'profileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256',\n        name: 'pubId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'address',\n        name: 'module',\n        type: 'address',\n      },\n    ],\n    name: 'isActionModuleEnabledInPublication',\n    outputs: [\n      {\n        internalType: 'bool',\n        name: '',\n        type: 'bool',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'owner',\n        type: 'address',\n      },\n      {\n        internalType: 'address',\n        name: 'operator',\n        type: 'address',\n      },\n    ],\n    name: 'isApprovedForAll',\n    outputs: [\n      {\n        internalType: 'bool',\n        name: '',\n        type: 'bool',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'profileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256',\n        name: 'byProfileId',\n        type: 'uint256',\n      },\n    ],\n    name: 'isBlocked',\n    outputs: [\n      {\n        internalType: 'bool',\n        name: '',\n        type: 'bool',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'delegatorProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'address',\n        name: 'delegatedExecutor',\n        type: 'address',\n      },\n    ],\n    name: 'isDelegatedExecutorApproved',\n    outputs: [\n      {\n        internalType: 'bool',\n        name: '',\n        type: 'bool',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'delegatorProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'address',\n        name: 'delegatedExecutor',\n        type: 'address',\n      },\n      {\n        internalType: 'uint64',\n        name: 'configNumber',\n        type: 'uint64',\n      },\n    ],\n    name: 'isDelegatedExecutorApproved',\n    outputs: [\n      {\n        internalType: 'bool',\n        name: '',\n        type: 'bool',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'followerProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256',\n        name: 'followedProfileId',\n        type: 'uint256',\n      },\n    ],\n    name: 'isFollowing',\n    outputs: [\n      {\n        internalType: 'bool',\n        name: '',\n        type: 'bool',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'profileCreator',\n        type: 'address',\n      },\n    ],\n    name: 'isProfileCreatorWhitelisted',\n    outputs: [\n      {\n        internalType: 'bool',\n        name: '',\n        type: 'bool',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'mintTimestampOf',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'profileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'string',\n            name: 'metadataURI',\n            type: 'string',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedPubId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerProfileIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerPubIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.MirrorParams',\n        name: 'mirrorParams',\n        type: 'tuple',\n      },\n    ],\n    name: 'mirror',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'profileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'string',\n            name: 'metadataURI',\n            type: 'string',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedPubId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerProfileIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerPubIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.MirrorParams',\n        name: 'mirrorParams',\n        type: 'tuple',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'mirrorWithSig',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'name',\n    outputs: [\n      {\n        internalType: 'string',\n        name: '',\n        type: 'string',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'signer',\n        type: 'address',\n      },\n    ],\n    name: 'nonces',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'ownerOf',\n    outputs: [\n      {\n        internalType: 'address',\n        name: '',\n        type: 'address',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'profileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'string',\n            name: 'contentURI',\n            type: 'string',\n          },\n          {\n            internalType: 'address[]',\n            name: 'actionModules',\n            type: 'address[]',\n          },\n          {\n            internalType: 'bytes[]',\n            name: 'actionModulesInitDatas',\n            type: 'bytes[]',\n          },\n          {\n            internalType: 'address',\n            name: 'referenceModule',\n            type: 'address',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleInitData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.PostParams',\n        name: 'postParams',\n        type: 'tuple',\n      },\n    ],\n    name: 'post',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'profileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'string',\n            name: 'contentURI',\n            type: 'string',\n          },\n          {\n            internalType: 'address[]',\n            name: 'actionModules',\n            type: 'address[]',\n          },\n          {\n            internalType: 'bytes[]',\n            name: 'actionModulesInitDatas',\n            type: 'bytes[]',\n          },\n          {\n            internalType: 'address',\n            name: 'referenceModule',\n            type: 'address',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleInitData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.PostParams',\n        name: 'postParams',\n        type: 'tuple',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'postWithSig',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'profileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'string',\n            name: 'contentURI',\n            type: 'string',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedPubId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerProfileIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerPubIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleData',\n            type: 'bytes',\n          },\n          {\n            internalType: 'address[]',\n            name: 'actionModules',\n            type: 'address[]',\n          },\n          {\n            internalType: 'bytes[]',\n            name: 'actionModulesInitDatas',\n            type: 'bytes[]',\n          },\n          {\n            internalType: 'address',\n            name: 'referenceModule',\n            type: 'address',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleInitData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.QuoteParams',\n        name: 'quoteParams',\n        type: 'tuple',\n      },\n    ],\n    name: 'quote',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        components: [\n          {\n            internalType: 'uint256',\n            name: 'profileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'string',\n            name: 'contentURI',\n            type: 'string',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedProfileId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256',\n            name: 'pointedPubId',\n            type: 'uint256',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerProfileIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'uint256[]',\n            name: 'referrerPubIds',\n            type: 'uint256[]',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleData',\n            type: 'bytes',\n          },\n          {\n            internalType: 'address[]',\n            name: 'actionModules',\n            type: 'address[]',\n          },\n          {\n            internalType: 'bytes[]',\n            name: 'actionModulesInitDatas',\n            type: 'bytes[]',\n          },\n          {\n            internalType: 'address',\n            name: 'referenceModule',\n            type: 'address',\n          },\n          {\n            internalType: 'bytes',\n            name: 'referenceModuleInitData',\n            type: 'bytes',\n          },\n        ],\n        internalType: 'struct Types.QuoteParams',\n        name: 'quoteParams',\n        type: 'tuple',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'quoteWithSig',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256',\n        name: 'salePrice',\n        type: 'uint256',\n      },\n    ],\n    name: 'royaltyInfo',\n    outputs: [\n      {\n        internalType: 'address',\n        name: '',\n        type: 'address',\n      },\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'from',\n        type: 'address',\n      },\n      {\n        internalType: 'address',\n        name: 'to',\n        type: 'address',\n      },\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'safeTransferFrom',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'from',\n        type: 'address',\n      },\n      {\n        internalType: 'address',\n        name: 'to',\n        type: 'address',\n      },\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'bytes',\n        name: '_data',\n        type: 'bytes',\n      },\n    ],\n    name: 'safeTransferFrom',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'operator',\n        type: 'address',\n      },\n      {\n        internalType: 'bool',\n        name: 'approved',\n        type: 'bool',\n      },\n    ],\n    name: 'setApprovalForAll',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'byProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256[]',\n        name: 'idsOfProfilesToSetBlockStatus',\n        type: 'uint256[]',\n      },\n      {\n        internalType: 'bool[]',\n        name: 'blockStatus',\n        type: 'bool[]',\n      },\n    ],\n    name: 'setBlockStatus',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'byProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256[]',\n        name: 'idsOfProfilesToSetBlockStatus',\n        type: 'uint256[]',\n      },\n      {\n        internalType: 'bool[]',\n        name: 'blockStatus',\n        type: 'bool[]',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'setBlockStatusWithSig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'newEmergencyAdmin',\n        type: 'address',\n      },\n    ],\n    name: 'setEmergencyAdmin',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'profileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'address',\n        name: 'followModule',\n        type: 'address',\n      },\n      {\n        internalType: 'bytes',\n        name: 'followModuleInitData',\n        type: 'bytes',\n      },\n    ],\n    name: 'setFollowModule',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'profileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'address',\n        name: 'followModule',\n        type: 'address',\n      },\n      {\n        internalType: 'bytes',\n        name: 'followModuleInitData',\n        type: 'bytes',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'setFollowModuleWithSig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'newGovernance',\n        type: 'address',\n      },\n    ],\n    name: 'setGovernance',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address[]',\n        name: 'migrationAdmins',\n        type: 'address[]',\n      },\n      {\n        internalType: 'bool',\n        name: 'whitelisted',\n        type: 'bool',\n      },\n    ],\n    name: 'setMigrationAdmins',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'profileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'string',\n        name: 'metadataURI',\n        type: 'string',\n      },\n    ],\n    name: 'setProfileMetadataURI',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'profileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'string',\n        name: 'metadataURI',\n        type: 'string',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'setProfileMetadataURIWithSig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'royaltiesInBasisPoints',\n        type: 'uint256',\n      },\n    ],\n    name: 'setRoyalty',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'enum Types.ProtocolState',\n        name: 'newState',\n        type: 'uint8',\n      },\n    ],\n    name: 'setState',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'newTreasury',\n        type: 'address',\n      },\n    ],\n    name: 'setTreasury',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint16',\n        name: 'newTreasuryFee',\n        type: 'uint16',\n      },\n    ],\n    name: 'setTreasuryFee',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'bytes4',\n        name: 'interfaceId',\n        type: 'bytes4',\n      },\n    ],\n    name: 'supportsInterface',\n    outputs: [\n      {\n        internalType: 'bool',\n        name: '',\n        type: 'bool',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'symbol',\n    outputs: [\n      {\n        internalType: 'string',\n        name: '',\n        type: 'string',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'tokenDataOf',\n    outputs: [\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'owner',\n            type: 'address',\n          },\n          {\n            internalType: 'uint96',\n            name: 'mintTimestamp',\n            type: 'uint96',\n          },\n        ],\n        internalType: 'struct Types.TokenData',\n        name: '',\n        type: 'tuple',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'tokenURI',\n    outputs: [\n      {\n        internalType: 'string',\n        name: '',\n        type: 'string',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [],\n    name: 'totalSupply',\n    outputs: [\n      {\n        internalType: 'uint256',\n        name: '',\n        type: 'uint256',\n      },\n    ],\n    stateMutability: 'view',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'from',\n        type: 'address',\n      },\n      {\n        internalType: 'address',\n        name: 'to',\n        type: 'address',\n      },\n      {\n        internalType: 'uint256',\n        name: 'tokenId',\n        type: 'uint256',\n      },\n    ],\n    name: 'transferFrom',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'unfollowerProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256[]',\n        name: 'idsOfProfilesToUnfollow',\n        type: 'uint256[]',\n      },\n    ],\n    name: 'unfollow',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'uint256',\n        name: 'unfollowerProfileId',\n        type: 'uint256',\n      },\n      {\n        internalType: 'uint256[]',\n        name: 'idsOfProfilesToUnfollow',\n        type: 'uint256[]',\n      },\n      {\n        components: [\n          {\n            internalType: 'address',\n            name: 'signer',\n            type: 'address',\n          },\n          {\n            internalType: 'uint8',\n            name: 'v',\n            type: 'uint8',\n          },\n          {\n            internalType: 'bytes32',\n            name: 'r',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'bytes32',\n            name: 's',\n            type: 'bytes32',\n          },\n          {\n            internalType: 'uint256',\n            name: 'deadline',\n            type: 'uint256',\n          },\n        ],\n        internalType: 'struct Types.EIP712Signature',\n        name: 'signature',\n        type: 'tuple',\n      },\n    ],\n    name: 'unfollowWithSig',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n  {\n    inputs: [\n      {\n        internalType: 'address',\n        name: 'profileCreator',\n        type: 'address',\n      },\n      {\n        internalType: 'bool',\n        name: 'whitelist',\n        type: 'bool',\n      },\n    ],\n    name: 'whitelistProfileCreator',\n    outputs: [],\n    stateMutability: 'nonpayable',\n    type: 'function',\n  },\n];\n"
  },
  {
    "path": "momoka-node/src/evm/ethereum.ts",
    "content": "import { BigNumber, ethers } from 'ethers';\nimport { Deployment, Environment, environmentToLensHubContract } from '../common/environment';\nimport { retryWithTimeout } from '../common/helpers';\nimport { PromiseResult, failure, success } from '../data-availability-models/da-result';\nimport { MomokaValidatorError } from '../data-availability-models/validator-errors';\nimport { JSONRPCWithTimeout, RATE_LIMIT_TIME } from '../input-output/json-rpc-with-timeout';\nimport { JSONRPCMethods } from './jsonrpc-methods';\nimport { numberToHex } from '../utils/number-to-hex';\n\nexport interface EthereumNode {\n  environment: Environment;\n  nodeUrl: string;\n  /**\n   * Only if you want to use staging/local environment\n   * only use this if you know what you are doing!\n   */\n  deployment?: Deployment | undefined;\n}\n\nexport const EMPTY_BYTE = '0x';\n\n/**\n * Executes a simulation transaction on the given Ethereum node.\n * @param data - The transaction data to be executed.\n * @param blockNumber - The block number to use for the transaction.\n * @param ethereumNode - The Ethereum node to use for the transaction.\n * @returns A `DAResult` with the result of the transaction or an error message.\n */\nexport const executeSimulationTransaction = async (\n  data: string,\n  blockNumber: number,\n  ethereumNode: EthereumNode\n): PromiseResult<string> => {\n  try {\n    return await retryWithTimeout(\n      async () => {\n        const ethCall = await JSONRPCWithTimeout<string>(\n          ethereumNode.nodeUrl,\n          JSONRPCMethods.eth_call,\n          [\n            {\n              to: environmentToLensHubContract(ethereumNode.environment),\n              data,\n            },\n            numberToHex(blockNumber),\n          ],\n          true\n        );\n\n        if (!ethCall) {\n          throw new Error('eth_call returned undefined');\n        }\n\n        return success(ethCall);\n      },\n      {\n        delayMs: RATE_LIMIT_TIME,\n      }\n    );\n  } catch (_error) {\n    return failure(MomokaValidatorError.SIMULATION_NODE_COULD_NOT_RUN);\n  }\n};\n\n/**\n * Check if a block hash exists for potential reorgs\n * @param blockHash - The transaction data to be executed.\n * @param ethereumNode - The Ethereum node to use for the transaction.\n * @returns A `DAResult` with the result of the transaction or an error message.\n */\nexport const blockHashExists = async (\n  blockHash: string,\n  ethereumNode: EthereumNode\n): PromiseResult<boolean> => {\n  try {\n    return await retryWithTimeout(\n      async () => {\n        // this returns a full block so can extend typings if you need anything more\n        const block = await JSONRPCWithTimeout<{ transactions: string[] }>(\n          ethereumNode.nodeUrl,\n          JSONRPCMethods.eth_getBlockByHash,\n          [blockHash, false]\n        );\n\n        if (!block) {\n          return success(false);\n        }\n\n        return success(true);\n      },\n      {\n        delayMs: RATE_LIMIT_TIME,\n      }\n    );\n  } catch (_error) {\n    return failure(MomokaValidatorError.SIMULATION_NODE_COULD_NOT_RUN);\n  }\n};\n\n/**\n * Parse an Ethereum signature string and add a deadline timestamp to it.\n * @param signature - The signature string to parse.\n * @param deadline - The deadline timestamp to add to the signature.\n * @returns An object containing the parsed signature and deadline.\n */\nexport const parseSignature = (\n  signature: string,\n  deadline: number\n): {\n  r: string;\n  s: string;\n  v: number;\n  deadline: number;\n} => {\n  const splitSign = ethers.utils.splitSignature(signature);\n  return {\n    r: splitSign.r,\n    s: splitSign.s,\n    v: splitSign.v,\n    deadline,\n  };\n};\n\nexport interface BlockInfo {\n  number: number;\n  timestamp: number;\n}\n\n/**\n * Returns information about a block specified by either block hash or block tag\n * @param blockHashOrBlockTag The hash or tag of the block to retrieve information for\n * @param ethereumNode The Ethereum node to use for the request\n * @returns A promise that resolves to an object containing block number and timestamp\n * @throws An error if the request fails and exceeds the maximum number of retries\n */\nexport const getBlock = async (\n  blockHashOrBlockTag: ethers.providers.BlockTag,\n  ethereumNode: EthereumNode\n): Promise<BlockInfo> => {\n  return await retryWithTimeout(\n    async () => {\n      if (typeof blockHashOrBlockTag === 'number') {\n        blockHashOrBlockTag = numberToHex(blockHashOrBlockTag);\n      }\n\n      const result: { number: string; timestamp: string } = await JSONRPCWithTimeout(\n        ethereumNode.nodeUrl,\n        JSONRPCMethods.eth_getBlockByNumber,\n        [blockHashOrBlockTag, false]\n      );\n\n      return {\n        number: BigNumber.from(result.number).toNumber(),\n        timestamp: BigNumber.from(result.timestamp).toNumber(),\n      };\n    },\n    {\n      delayMs: RATE_LIMIT_TIME,\n    }\n  );\n};\n"
  },
  {
    "path": "momoka-node/src/evm/gateway/LensHubV1Gateway.ts",
    "content": "import { EthereumNode } from '../ethereum';\nimport { Interface } from 'ethers/lib/utils';\nimport { LENS_HUB_V1_ABI } from '../contract-lens/lens-hub-v1-contract-abi';\nimport { retryWithTimeout } from '../../common/helpers';\nimport { JSONRPCWithTimeout, RATE_LIMIT_TIME } from '../../input-output/json-rpc-with-timeout';\nimport { JSONRPCMethods } from '../jsonrpc-methods';\nimport { environmentToLensHubContract } from '../../common/environment';\nimport { failure, PromiseResult, success } from '../../data-availability-models/da-result';\nimport { BigNumber, ethers } from 'ethers';\nimport { MomokaValidatorError } from '../../data-availability-models/validator-errors';\nimport { numberToHex } from '../../utils/number-to-hex';\nimport { ContractCallContext, Multicall } from 'ethereum-multicall';\nimport { PostWithSig_DispatcherRequest } from '../abi-types/LensHubV1';\n\nconst DALensHubInterface = new Interface(LENS_HUB_V1_ABI);\n\nconst contractInterface = new ethers.utils.Interface(Multicall.ABI);\n\nexport class LensHubV1Gateway {\n  constructor(private readonly ethereumNode: EthereumNode) {}\n\n  /**\n   * Generates simulation data for the postWithSig or postWithSig_Dispatcher function of the DAlens Hub contract.\n   * @param signedByDelegate - Indicates whether the signature was signed by the delegate.\n   * @param sigRequest - The signature request.\n   * @returns The simulation data or an error result.\n   *          turned into a promise as its minimum CPU intensive\n   */\n  generatePostSimulationData(\n    signedByDelegate: boolean,\n    sigRequest: PostWithSig_DispatcherRequest\n  ): PromiseResult<string> {\n    try {\n      const result = DALensHubInterface.encodeFunctionData(\n        signedByDelegate ? 'postWithSig_Dispatcher' : 'postWithSig',\n        [sigRequest]\n      );\n\n      return Promise.resolve(success(result));\n    } catch (e) {\n      return Promise.resolve(failure(MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA));\n    }\n  }\n\n  /**\n   * Fetches on-chain details for a given Lens Profile.\n   * @param blockNumber The block number at which to query the contract.\n   * @param profileId The ID of the Lens Profile.\n   * @param signedByAddress The address of the user who signed the transaction.\n   * @returns An object containing the on-chain details of the Lens Profile.\n   */\n  async getOnChainProfileDetails(\n    blockNumber: number,\n    profileId: string,\n    signedByAddress: string\n  ): PromiseResult<{\n    sigNonce: number;\n    currentPublicationId: string;\n    dispatcherAddress: string;\n    ownerOfAddress: string;\n  }> {\n    // Create a new Multicall instance\n    const multicall = new Multicall({\n      nodeUrl: this.ethereumNode.nodeUrl,\n      tryAggregate: true,\n    });\n\n    // Define the contract call context for the Lens Hub contract.\n    const contractCallContext: ContractCallContext = {\n      reference: 'onChainProfileDetails',\n      contractAddress: environmentToLensHubContract(this.ethereumNode.environment),\n      abi: LENS_HUB_V1_ABI,\n      calls: [\n        {\n          reference: 'sigNonces',\n          methodName: 'sigNonces',\n          methodParameters: [signedByAddress],\n        },\n        {\n          reference: 'getPubCount',\n          methodName: 'getPubCount',\n          methodParameters: [profileId],\n        },\n        {\n          reference: 'getDispatcher',\n          methodName: 'getDispatcher',\n          methodParameters: [profileId],\n        },\n        {\n          reference: 'ownerOf',\n          methodName: 'ownerOf',\n          methodParameters: [profileId],\n        },\n      ],\n    };\n\n    // we go a bespoke way so we can use our own http library and not ethers\n    // to be in full control\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore - use internal methods from mutlicall\n    const calls = multicall.mapCallContextToMatchContractFormat(\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore - use internal methods from mutlicall\n      multicall.buildAggregateCallContext([contractCallContext])\n    );\n    const encodedData = contractInterface.encodeFunctionData('tryBlockAndAggregate', [true, calls]);\n\n    try {\n      return await retryWithTimeout(\n        async () => {\n          const result = await JSONRPCWithTimeout<string>(\n            this.ethereumNode.nodeUrl,\n            JSONRPCMethods.eth_call,\n            [\n              {\n                // multicall 3 address\n                to: '0xcA11bde05977b3631167028862bE2a173976CA11',\n                data: encodedData,\n              },\n              numberToHex(blockNumber),\n            ]\n          );\n\n          const functionFragment = contractInterface.getFunction('tryBlockAndAggregate');\n          const outputTypes = functionFragment.outputs!;\n\n          const decodedResultData = ethers.utils.defaultAbiCoder.decode(outputTypes, result);\n          const resultData = decodedResultData[2];\n\n          // bit ugly but we need to decode the return data\n          // we know the order of stuff from the above ContractCallContext::calls\n          // but as we using a more bespoke approach we can use index here!\n          return success({\n            sigNonce: BigNumber.from(resultData[0].returnData).toNumber(),\n            currentPublicationId: BigNumber.from(resultData[1].returnData).toHexString(),\n            dispatcherAddress: ethers.utils.defaultAbiCoder.decode(\n              ['address'],\n              resultData[2].returnData\n            )[0],\n            ownerOfAddress: ethers.utils.defaultAbiCoder.decode(\n              ['address'],\n              resultData[3].returnData\n            )[0],\n          });\n        },\n        {\n          delayMs: RATE_LIMIT_TIME,\n        }\n      );\n    } catch (_error) {\n      return failure(MomokaValidatorError.DATA_CANT_BE_READ_FROM_NODE);\n    }\n  }\n\n  /**\n   * Returns the number of published data availability proofs for a given profile ID and block number.\n   * @param profileId The profile ID to retrieve the published proof count for.\n   * @param blockNumber The block number to retrieve the published proof count at.\n   * @returns The number of published data availability proofs for the specified profile ID and block number.\n   */\n  async getLensPubCount(profileId: string, blockNumber: number): PromiseResult<BigNumber> {\n    const encodedData = DALensHubInterface.encodeFunctionData('getPubCount', [profileId]);\n\n    try {\n      return await retryWithTimeout(\n        async () => {\n          const ethCall = await JSONRPCWithTimeout<string>(\n            this.ethereumNode.nodeUrl,\n            JSONRPCMethods.eth_call,\n            [\n              {\n                to: environmentToLensHubContract(this.ethereumNode.environment),\n                data: encodedData,\n              },\n              numberToHex(blockNumber),\n            ]\n          );\n\n          if (!ethCall) {\n            throw new Error('eth_call returned undefined');\n          }\n\n          return success(BigNumber.from(ethCall));\n        },\n        {\n          delayMs: RATE_LIMIT_TIME,\n        }\n      );\n    } catch (_error) {\n      return failure(MomokaValidatorError.DATA_CANT_BE_READ_FROM_NODE);\n    }\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/evm/gateway/LensHubV2Gateway.ts",
    "content": "import { EthereumNode } from '../ethereum';\nimport { Interface } from 'ethers/lib/utils';\nimport { retryWithTimeout } from '../../common/helpers';\nimport { JSONRPCWithTimeout, RATE_LIMIT_TIME } from '../../input-output/json-rpc-with-timeout';\nimport { JSONRPCMethods } from '../jsonrpc-methods';\nimport { environmentToLensHubContract } from '../../common/environment';\nimport { failure, PromiseResult, success } from '../../data-availability-models/da-result';\nimport { BigNumber, ethers } from 'ethers';\nimport { MomokaValidatorError } from '../../data-availability-models/validator-errors';\nimport { numberToHex } from '../../utils/number-to-hex';\nimport { ContractCallContext, Multicall } from 'ethereum-multicall';\nimport { LENS_HUB_V2_ABI } from '../contract-lens/lens-hub-v2-contract-abi';\nimport { PostParamsRequest, SignatureRequest } from '../abi-types/LensHubV2';\n\nconst DALensHubInterface = new Interface(LENS_HUB_V2_ABI);\n\nconst contractInterface = new ethers.utils.Interface(Multicall.ABI);\n\nexport class LensHubV2Gateway {\n  constructor(private readonly ethereumNode: EthereumNode) {}\n\n  /**\n   * Generates simulation data for the postWithSig function of the DAlens Hub contract.\n   * @param params - The parameters.\n   * @param signature - The signature.\n   * @returns The simulation data or an error result.\n   *          turned into a promise as its minimum CPU intensive\n   */\n  generatePostSimulationData(\n    params: PostParamsRequest,\n    signature: SignatureRequest\n  ): PromiseResult<string> {\n    try {\n      const result = DALensHubInterface.encodeFunctionData('postWithSig', [params, signature]);\n\n      return Promise.resolve(success(result));\n    } catch (e) {\n      return Promise.resolve(failure(MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA));\n    }\n  }\n\n  /**\n   * Fetches on-chain details for a given Lens Profile.\n   * @param blockNumber The block number at which to query the contract.\n   * @param profileId The ID of the Lens Profile.\n   * @param signedByAddress The address of the user who signed the transaction.\n   * @returns An object containing the on-chain details of the Lens Profile.\n   */\n  async getOnChainProfileDetails(\n    blockNumber: number,\n    profileId: string,\n    signedByAddress: string\n  ): PromiseResult<{\n    nonces: number;\n    currentPublicationId: string;\n    isSignerApprovedExecutor: boolean;\n    ownerOfAddress: string;\n  }> {\n    // Create a new Multicall instance\n    const multicall = new Multicall({\n      nodeUrl: this.ethereumNode.nodeUrl,\n      tryAggregate: true,\n    });\n\n    // Define the contract call context for the Lens Hub contract.\n    const contractCallContext: ContractCallContext = {\n      reference: 'onChainProfileDetails',\n      contractAddress: environmentToLensHubContract(this.ethereumNode.environment),\n      abi: LENS_HUB_V2_ABI,\n      calls: [\n        {\n          reference: 'nonces',\n          methodName: 'nonces',\n          methodParameters: [signedByAddress],\n        },\n        {\n          reference: 'getProfile',\n          methodName: 'getProfile',\n          methodParameters: [profileId],\n        },\n        {\n          reference: 'isDelegatedExecutorApproved',\n          methodName: 'isDelegatedExecutorApproved(uint256, address)',\n          methodParameters: [profileId, signedByAddress],\n        },\n        {\n          reference: 'ownerOf',\n          methodName: 'ownerOf',\n          methodParameters: [profileId],\n        },\n      ],\n    };\n\n    // we go a bespoke way so we can use our own http library and not ethers\n    // to be in full control\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore - use internal methods from mutlicall\n    const calls = multicall.mapCallContextToMatchContractFormat(\n      // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n      // @ts-ignore - use internal methods from mutlicall\n      multicall.buildAggregateCallContext([contractCallContext])\n    );\n    const encodedData = contractInterface.encodeFunctionData('tryBlockAndAggregate', [true, calls]);\n\n    try {\n      return await retryWithTimeout(\n        async () => {\n          const result = await JSONRPCWithTimeout<string>(\n            this.ethereumNode.nodeUrl,\n            JSONRPCMethods.eth_call,\n            [\n              {\n                // multicall 3 address\n                to: '0xcA11bde05977b3631167028862bE2a173976CA11',\n                data: encodedData,\n              },\n              numberToHex(blockNumber),\n            ]\n          );\n\n          const functionFragment = contractInterface.getFunction('tryBlockAndAggregate');\n          const outputTypes = functionFragment.outputs!;\n\n          const decodedResultData = ethers.utils.defaultAbiCoder.decode(outputTypes, result);\n          const resultData = decodedResultData[2];\n\n          const [decodedGetProfileResponse] = DALensHubInterface.decodeFunctionResult(\n            'getProfile',\n            resultData[1].returnData\n          );\n\n          // bit ugly but we need to decode the return data\n          // we know the order of stuff from the above ContractCallContext::calls\n          // but as we using a more bespoke approach we can use index here!\n          return success({\n            nonces: BigNumber.from(resultData[0].returnData).toNumber(),\n            currentPublicationId: BigNumber.from(decodedGetProfileResponse[0]).toHexString(),\n            isSignerApprovedExecutor: ethers.utils.defaultAbiCoder.decode(\n              ['bool'],\n              resultData[2].returnData\n            )[0],\n            ownerOfAddress: ethers.utils.defaultAbiCoder.decode(\n              ['address'],\n              resultData[3].returnData\n            )[0],\n          });\n        },\n        {\n          delayMs: RATE_LIMIT_TIME,\n        }\n      );\n    } catch (_error) {\n      return failure(MomokaValidatorError.DATA_CANT_BE_READ_FROM_NODE);\n    }\n  }\n\n  /**\n   * Returns the number of published data availability proofs for a given profile ID and block number.\n   * @param profileId The profile ID to retrieve the published proof count for.\n   * @param blockNumber The block number to retrieve the published proof count at.\n   * @returns The number of published data availability proofs for the specified profile ID and block number.\n   */\n  async getLensPubCount(profileId: string, blockNumber: number): PromiseResult<BigNumber> {\n    const encodedData = DALensHubInterface.encodeFunctionData('getProfile', [profileId]);\n\n    try {\n      return await retryWithTimeout(\n        async () => {\n          const ethCall = await JSONRPCWithTimeout<string>(\n            this.ethereumNode.nodeUrl,\n            JSONRPCMethods.eth_call,\n            [\n              {\n                to: environmentToLensHubContract(this.ethereumNode.environment),\n                data: encodedData,\n              },\n              numberToHex(blockNumber),\n            ]\n          );\n\n          if (!ethCall) {\n            throw new Error('eth_call returned undefined');\n          }\n\n          const [decodedGetProfileResponse] = DALensHubInterface.decodeFunctionResult(\n            'getProfile',\n            ethCall\n          );\n\n          return success(BigNumber.from(decodedGetProfileResponse[0]));\n        },\n        {\n          delayMs: RATE_LIMIT_TIME,\n        }\n      );\n    } catch {\n      return failure(MomokaValidatorError.DATA_CANT_BE_READ_FROM_NODE);\n    }\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/evm/jsonrpc-methods.ts",
    "content": "/**\n * JSON RPC methods we use\n */\nexport enum JSONRPCMethods {\n  eth_getBlockByNumber = 'eth_getBlockByNumber',\n  eth_call = 'eth_call',\n  eth_getBlockByHash = 'eth_getBlockByHash',\n  anvil_reset = 'anvil_reset',\n}\n"
  },
  {
    "path": "momoka-node/src/graphql/data-availability-transactions.graphql",
    "content": "query DataAvailabilityTransactions(\n  $owners: [String!]\n  $limit: Int\n  $after: String\n  $order: SortOrder\n) {\n  transactions(owners: $owners, limit: $limit, after: $after, order: $order, hasTags: true) {\n    edges {\n      node {\n        id\n        address\n      }\n      cursor\n    }\n    pageInfo {\n      endCursor\n      hasNextPage\n    }\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/graphql/generated.ts",
    "content": "import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/core';\nexport type Maybe<T> = T | null;\nexport type InputMaybe<T> = Maybe<T>;\nexport type Exact<T extends { [key: string]: unknown }> = { [K in keyof T]: T[K] };\nexport type MakeOptional<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]?: Maybe<T[SubKey]> };\nexport type MakeMaybe<T, K extends keyof T> = Omit<T, K> & { [SubKey in K]: Maybe<T[SubKey]> };\n/** All built-in and custom scalars, mapped to their actual values */\nexport type Scalars = {\n  ID: string;\n  String: string;\n  Boolean: boolean;\n  Int: number;\n  Float: number;\n  BigInt: any;\n};\n\nexport type PageInfo = {\n  __typename?: 'PageInfo';\n  endCursor?: Maybe<Scalars['String']>;\n  hasNextPage: Scalars['Boolean'];\n};\n\nexport type Query = {\n  __typename?: 'Query';\n  transactions?: Maybe<TransactionConnection>;\n};\n\nexport type QueryTransactionsArgs = {\n  after?: InputMaybe<Scalars['String']>;\n  currency?: InputMaybe<Scalars['String']>;\n  hasTags?: InputMaybe<Scalars['Boolean']>;\n  ids?: InputMaybe<Array<Scalars['String']>>;\n  limit?: InputMaybe<Scalars['Int']>;\n  order?: InputMaybe<SortOrder>;\n  owners?: InputMaybe<Array<Scalars['String']>>;\n  tags?: InputMaybe<Array<TagFilter>>;\n};\n\nexport type Receipt = {\n  __typename?: 'Receipt';\n  signature: Scalars['String'];\n  timestamp: Scalars['BigInt'];\n  version: Scalars['String'];\n};\n\nexport enum SortOrder {\n  Asc = 'ASC',\n  Desc = 'DESC',\n}\n\nexport type Tag = {\n  __typename?: 'Tag';\n  name: Scalars['String'];\n  value: Scalars['String'];\n};\n\nexport type TagFilter = {\n  name: Scalars['String'];\n  values: Array<Scalars['String']>;\n};\n\nexport type Transaction = {\n  __typename?: 'Transaction';\n  address: Scalars['String'];\n  currency: Scalars['String'];\n  id: Scalars['String'];\n  receipt?: Maybe<Receipt>;\n  signature?: Maybe<Scalars['String']>;\n  tags: Array<Tag>;\n  timestamp: Scalars['BigInt'];\n};\n\nexport type TransactionConnection = {\n  __typename?: 'TransactionConnection';\n  edges?: Maybe<Array<Maybe<TransactionEdge>>>;\n  pageInfo?: Maybe<PageInfo>;\n};\n\nexport type TransactionEdge = {\n  __typename?: 'TransactionEdge';\n  cursor: Scalars['String'];\n  node: Transaction;\n};\n\nexport type DataAvailabilityTransactionsQueryVariables = Exact<{\n  owners?: InputMaybe<Array<Scalars['String']> | Scalars['String']>;\n  limit?: InputMaybe<Scalars['Int']>;\n  after?: InputMaybe<Scalars['String']>;\n}>;\n\nexport type DataAvailabilityTransactionsQuery = {\n  __typename?: 'Query';\n  transactions?: {\n    __typename?: 'TransactionConnection';\n    edges?: Array<{\n      __typename?: 'TransactionEdge';\n      cursor: string;\n      node: { __typename?: 'Transaction'; id: string; address: string };\n    } | null> | null;\n    pageInfo?: { __typename?: 'PageInfo'; endCursor?: string | null; hasNextPage: boolean } | null;\n  } | null;\n};\n\nexport const DataAvailabilityTransactionsDocument = {\n  kind: 'Document',\n  definitions: [\n    {\n      kind: 'OperationDefinition',\n      operation: 'query',\n      name: { kind: 'Name', value: 'DataAvailabilityTransactions' },\n      variableDefinitions: [\n        {\n          kind: 'VariableDefinition',\n          variable: { kind: 'Variable', name: { kind: 'Name', value: 'owners' } },\n          type: {\n            kind: 'ListType',\n            type: {\n              kind: 'NonNullType',\n              type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } },\n            },\n          },\n        },\n        {\n          kind: 'VariableDefinition',\n          variable: { kind: 'Variable', name: { kind: 'Name', value: 'limit' } },\n          type: { kind: 'NamedType', name: { kind: 'Name', value: 'Int' } },\n        },\n        {\n          kind: 'VariableDefinition',\n          variable: { kind: 'Variable', name: { kind: 'Name', value: 'after' } },\n          type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } },\n        },\n        {\n          kind: 'VariableDefinition',\n          variable: { kind: 'Variable', name: { kind: 'Name', value: 'order' } },\n          type: { kind: 'NamedType', name: { kind: 'Name', value: 'SortOrder' } },\n        },\n      ],\n      selectionSet: {\n        kind: 'SelectionSet',\n        selections: [\n          {\n            kind: 'Field',\n            name: { kind: 'Name', value: 'transactions' },\n            arguments: [\n              {\n                kind: 'Argument',\n                name: { kind: 'Name', value: 'owners' },\n                value: { kind: 'Variable', name: { kind: 'Name', value: 'owners' } },\n              },\n              {\n                kind: 'Argument',\n                name: { kind: 'Name', value: 'limit' },\n                value: { kind: 'Variable', name: { kind: 'Name', value: 'limit' } },\n              },\n              {\n                kind: 'Argument',\n                name: { kind: 'Name', value: 'after' },\n                value: { kind: 'Variable', name: { kind: 'Name', value: 'after' } },\n              },\n              {\n                kind: 'Argument',\n                name: { kind: 'Name', value: 'order' },\n                value: { kind: 'Variable', name: { kind: 'Name', value: 'order' } },\n              },\n              {\n                kind: 'Argument',\n                name: { kind: 'Name', value: 'hasTags' },\n                value: { kind: 'BooleanValue', value: true },\n              },\n            ],\n            selectionSet: {\n              kind: 'SelectionSet',\n              selections: [\n                {\n                  kind: 'Field',\n                  name: { kind: 'Name', value: 'edges' },\n                  selectionSet: {\n                    kind: 'SelectionSet',\n                    selections: [\n                      {\n                        kind: 'Field',\n                        name: { kind: 'Name', value: 'node' },\n                        selectionSet: {\n                          kind: 'SelectionSet',\n                          selections: [\n                            { kind: 'Field', name: { kind: 'Name', value: 'id' } },\n                            { kind: 'Field', name: { kind: 'Name', value: 'address' } },\n                          ],\n                        },\n                      },\n                      { kind: 'Field', name: { kind: 'Name', value: 'cursor' } },\n                    ],\n                  },\n                },\n                {\n                  kind: 'Field',\n                  name: { kind: 'Name', value: 'pageInfo' },\n                  selectionSet: {\n                    kind: 'SelectionSet',\n                    selections: [\n                      { kind: 'Field', name: { kind: 'Name', value: 'endCursor' } },\n                      { kind: 'Field', name: { kind: 'Name', value: 'hasNextPage' } },\n                    ],\n                  },\n                },\n              ],\n            },\n          },\n        ],\n      },\n    },\n  ],\n} as unknown as DocumentNode<\n  DataAvailabilityTransactionsQuery,\n  DataAvailabilityTransactionsQueryVariables\n>;\n"
  },
  {
    "path": "momoka-node/src/graphql/urql.client.ts",
    "content": "import { createClient } from '@urql/core';\nimport { BUNDLR_NODE_GRAPHQL } from '../input-output/bundlr/bundlr-config';\n\nexport const client = createClient({\n  url: BUNDLR_NODE_GRAPHQL,\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  fetch: fetch as any,\n  requestPolicy: 'network-only',\n});\n"
  },
  {
    "path": "momoka-node/src/index.ts",
    "content": "export { Deployment, Environment } from './common/environment';\nexport {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from './data-availability-models/publications/data-availability-structure-publication';\nexport { MomokaValidatorError } from './data-availability-models/validator-errors';\nexport { EthereumNode } from './evm/ethereum';\nexport {\n  TxValidatedFailureResult,\n  TxValidatedResult,\n  TxValidatedSuccessResult,\n} from './input-output/tx-validated-results';\nexport { checkDAProof } from './proofs/check-da-proof';\nexport * from './submitters';\nexport * from './watchers/models/stream.type';\nexport {\n  StartDATrustingIndexingRequest,\n  startDATrustingIndexing,\n} from './watchers/trusting-indexing.watcher';\nexport { startDAVerifierNode } from './watchers/verifier.watcher';\nexport { MomokaActionTypes } from './data-availability-models/data-availability-action-types';\nexport { MomokaProvider } from './data-availability-models/data-availability-provider';\n"
  },
  {
    "path": "momoka-node/src/input-output/arweave/get-arweave-by-id.api.ts",
    "content": "import { AxiosProvider } from '../../client/axios-provider';\nimport { TimeoutError } from '../common';\nimport { fetchWithTimeout } from '../fetch-with-timeout';\n\n/**\n * Retrieves data associated with a given transaction ID using the arweave gateway.\n * @param txId The transaction ID to retrieve data for.\n * @param options The options for the request.\n * @returns The data associated with the transaction, or `null` if the transaction cannot be found, or `TimeoutError` if the request times out.\n * @note This function is not used internally on the data availability node as it is too slow. Even so you can use this if you wish on a fork or anything else.\n */\nexport const getArweaveByIdAPI = <T>(txId: string): Promise<T | TimeoutError | null> => {\n  return fetchWithTimeout<T>(`https://arweave.net/${txId}`, { provider: new AxiosProvider() });\n};\n"
  },
  {
    "path": "momoka-node/src/input-output/bundlr/bundlr-config.ts",
    "content": "/**\n * The URL for the Lens Bundlr node.\n */\nexport const BUNDLR_NODE = 'https://lens.bundlr.network/';\n\n/**\n * The URL for the GraphQL endpoint on the Lens Bundlr node.\n */\nexport const BUNDLR_NODE_GRAPHQL = `${BUNDLR_NODE}graphql`;\n\n/**\n * The base URL for transaction-related endpoints on the Lens Bundlr node.\n */\nexport const BUNDLR_NODE_TX = `${BUNDLR_NODE}tx/`;\n\n/**\n * The URL for the Lens Bundlr gateway.\n */\nexport const BUNDLR_GATEWAY = 'https://lens-gateway.bundlr.network/';\n\n/**\n * The base URL for transaction-related endpoints on the Lens Bundlr gateway.\n */\nexport const BUNDLR_GATEWAY_TX = `${BUNDLR_GATEWAY}tx/`;\n"
  },
  {
    "path": "momoka-node/src/input-output/bundlr/get-bundlr-bulk-txs.api.ts",
    "content": "import { retryWithTimeout } from '../../common/helpers';\nimport { TimeoutError, TIMEOUT_ERROR } from '../common';\nimport { postWithTimeout } from '../post-with-timeout';\nimport { BUNDLR_NODE } from './bundlr-config';\n\n/**\n * The response format for the `getBundlrBulkTxsAPI` function when it is successful.\n */\nexport interface BundlrBulkTxSuccess {\n  id: string;\n  address: string;\n  data: string;\n}\n\n/**\n * The response format for the `getBundlrBulkTxsAPI` function.\n */\nexport interface BundlrBulkTxsResponse {\n  success: BundlrBulkTxSuccess[];\n  failed: Record<string, string>;\n}\n\n/**\n * Sends a POST request to the Lens Bundlr API to retrieve data associated with multiple transaction IDs.\n * @param txIds The transaction IDs to retrieve data for.\n * @returns The data associated with the given transaction IDs, or `TimeoutError` if the request times out.\n */\nexport const getBundlrBulkTxsAPI = (\n  txIds: string[]\n): Promise<BundlrBulkTxsResponse | TimeoutError> => {\n  return retryWithTimeout(\n    async () => {\n      try {\n        return await postWithTimeout<BundlrBulkTxsResponse, string[]>(\n          `${BUNDLR_NODE}bulk/txs/data`,\n          txIds\n        );\n      } catch (error) {\n        return TIMEOUT_ERROR;\n      }\n    },\n    { maxRetries: 3, delayMs: 200 }\n  );\n};\n"
  },
  {
    "path": "momoka-node/src/input-output/bundlr/get-bundlr-by-id.api.ts",
    "content": "import { retryWithTimeout } from '../../common/helpers';\nimport { TIMEOUT_ERROR, TimeoutError } from '../common';\nimport { FetchProvider, fetchWithTimeout } from '../fetch-with-timeout';\nimport { BUNDLR_GATEWAY_TX } from './bundlr-config';\n\n/**\n * Sends a GET request to the Lens Bundlr API to retrieve data associated with a given transaction ID.\n * @param txId The transaction ID to retrieve data for.\n * @param options The options for the request.\n * @returns The data associated with the given transaction ID, or `null` if the transaction cannot be found, or `TimeoutError` if the request times out.\n */\nexport const getBundlrByIdAPI = <T>(\n  txId: string,\n  { provider }: { provider: FetchProvider }\n): Promise<T | TimeoutError | null> => {\n  return retryWithTimeout(\n    async () => {\n      try {\n        return await fetchWithTimeout<T>(`${BUNDLR_GATEWAY_TX}${txId}/data`, { provider });\n      } catch (error) {\n        return TIMEOUT_ERROR;\n      }\n    },\n    { maxRetries: 3, delayMs: 200 }\n  );\n};\n"
  },
  {
    "path": "momoka-node/src/input-output/bundlr/get-data-availability-transactions.api.ts",
    "content": "import { Deployment, Environment } from '../../common/environment';\nimport { DataAvailabilityTransactionsDocument } from '../../graphql/generated';\nimport { client } from '../../graphql/urql.client';\nimport { getSubmitters } from '../../submitters';\n\n/**\n * The response format for the `getDataAvailabilityTransactionsAPI` function.\n */\nexport interface getDataAvailabilityTransactionsAPIResponse {\n  edges: {\n    node: {\n      id: string;\n      address: string;\n    };\n    cursor: string;\n  }[];\n  pageInfo: {\n    hasNextPage: boolean;\n    endCursor: string | null;\n  };\n}\n\nexport enum DataAvailabilityTransactionsOrderTypes {\n  ASC = 'ASC',\n  DESC = 'DESC',\n}\n\n/**\n * Sends a query to the bundlr GraphQL API to retrieve data availability transactions.\n * @param environment The environment to retrieve transactions for.\n * @param deployment The deployment to retrieve transactions for, or `undefined` to retrieve transactions for all deployments.\n * @param cursor The cursor to use for paginating results, or `null` to retrieve the first page of results.\n * @returns The data availability transactions matching the given parameters.\n */\nexport const getDataAvailabilityTransactionsAPI = async (\n  environment: Environment,\n  deployment: Deployment | undefined,\n  cursor: string | null,\n  order: DataAvailabilityTransactionsOrderTypes,\n  limit = 1000\n): Promise<getDataAvailabilityTransactionsAPIResponse> => {\n  const result = await client\n    .query(DataAvailabilityTransactionsDocument, {\n      owners: getSubmitters(environment, deployment),\n      after: cursor,\n      order,\n      // max fetch is 1000\n      limit: limit <= 1000 ? limit : 1000,\n    })\n    .toPromise();\n\n  if (!result.data) {\n    throw new Error(\n      'No data returned from Bundlr GraphQL API - normally due to a network drop, will auto retry and 99.9% sort itself out when network is stable again.'\n    );\n  }\n\n  return result.data.transactions as getDataAvailabilityTransactionsAPIResponse;\n};\n"
  },
  {
    "path": "momoka-node/src/input-output/bundlr/get-owner-of-transaction.api.ts",
    "content": "import { retryWithTimeout } from '../../common/helpers';\nimport { TimeoutError } from '../common';\nimport { FetchProvider, fetchWithTimeout } from '../fetch-with-timeout';\nimport { BUNDLR_NODE_TX } from './bundlr-config';\n\n/**\n * Information about a Lens Bundlr transaction.\n */\ninterface BundlrTx {\n  id: string;\n  currency: string;\n  address: string;\n  owner: string;\n  signature: string;\n  target: string;\n  tags: {\n    name: string;\n    value: string;\n  }[];\n  anchor: string;\n  data_size: number;\n}\n\n/**\n * Sends a GET request to the Lens Bundlr API to retrieve the owner of a given transaction.\n * @param txId The ID of the transaction to retrieve the owner for.\n * @param options The options to use when sending the request.\n * @returns The owner of the transaction with the given ID, or `null` if the transaction cannot be found, or `TimeoutError` if the request times out.\n */\nexport const getOwnerOfTransactionAPI = (\n  txId: string,\n  { provider }: { provider: FetchProvider }\n): Promise<string | null | TimeoutError> => {\n  return retryWithTimeout(async () => {\n    const result = await fetchWithTimeout<BundlrTx>(`${BUNDLR_NODE_TX}${txId}`, {\n      provider,\n    });\n    if (!result) return null;\n    return result.address;\n  });\n};\n"
  },
  {
    "path": "momoka-node/src/input-output/common.ts",
    "content": "export const TIMEOUT_ERROR = 'timeout';\nexport type TimeoutError = 'timeout';\n"
  },
  {
    "path": "momoka-node/src/input-output/db.ts",
    "content": "import { existsSync, mkdirSync } from 'fs';\nimport { Level } from 'level';\nimport { DATimestampProofsResponse } from '../data-availability-models/data-availability-timestamp-proofs';\nimport {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../data-availability-models/publications/data-availability-structure-publication';\nimport { BlockInfo } from '../evm/ethereum';\nimport { invariant } from '../utils/invariant';\nimport { failedProofsPath, lensDAPath, pathResolver } from './paths';\nimport { TxValidatedResult } from './tx-validated-results';\n\nlet db: Level | undefined;\n\nexport enum DbReference {\n  block = 'block',\n  tx = 'tx',\n  tx_da_metadata = 'tx_da_metadata',\n  tx_timestamp_proof_metadata = 'tx_timestamp_proof_metadata',\n  tx_signature = 'tx_signature',\n  cursor = 'cursor',\n}\n\n/**\n * Starts the LevelDB database.\n */\nexport const startDb = async (): Promise<void> => {\n  invariant(!db, 'Database already started');\n\n  const path = await pathResolver();\n  const lens__da = await lensDAPath();\n  if (!existsSync(lens__da)) {\n    mkdirSync(lens__da);\n  }\n\n  const failedProofs = await failedProofsPath();\n  if (!existsSync(failedProofs)) {\n    mkdirSync(failedProofs);\n  }\n\n  const dbPath = path.join(lens__da, 'database');\n  if (!existsSync(dbPath)) {\n    mkdirSync(dbPath);\n  }\n\n  db = new Level(dbPath);\n};\n\n/**\n * Deletes an item from the database.\n * @param key - The key of the item to be deleted.\n */\nexport const deleteDb = (key: string): Promise<void> => {\n  if (!db) {\n    return Promise.resolve();\n  }\n\n  return db.del(key);\n};\n\n/**\n * Gets a transaction from the database.\n * @param txId - The ID of the transaction to get.\n * @returns The transaction if it exists, null otherwise.\n */\nexport const getTxDb = async (txId: string): Promise<TxValidatedResult | null> => {\n  if (!db) {\n    return null;\n  }\n\n  try {\n    const result = await db.get(`${DbReference.tx}:${txId}`);\n    return JSON.parse(result) as TxValidatedResult;\n  } catch (e) {\n    return null;\n  }\n};\n\n/**\n * Saves a transaction to the database.\n *\n * @param txId - The ID of the transaction to save.\n * @param result - The result of the transaction.\n */\nexport const saveTxDb = async (txId: string, result: TxValidatedResult): Promise<void> => {\n  if (!db) {\n    return;\n  }\n\n  try {\n    if (result.dataAvailabilityResult) {\n      await saveSignatureDb(result.dataAvailabilityResult.chainProofs.thisPublication.signature);\n    }\n    await db.put(`${DbReference.tx}:${txId}`, JSON.stringify(result));\n  } catch (error) {\n    throw new Error('`saveTxDb`- Could not write to into the db - critical error!');\n  }\n};\n\n/**\n * Gets a block from the database.\n *\n * @param blockNumber - The number of the block to get.\n * @returns The block if it exists, null otherwise.\n */\nexport const getBlockDb = async (blockNumber: number): Promise<BlockInfo | null> => {\n  if (!db) {\n    return null;\n  }\n\n  try {\n    const result = await db.get(`${DbReference.block}:${blockNumber}`);\n    return JSON.parse(result) as BlockInfo;\n  } catch (e) {\n    return null;\n  }\n};\n\n/**\n * Saves a block to the database.\n *\n * @param block - The block to save.\n */\nexport const saveBlockDb = async (block: BlockInfo): Promise<void> => {\n  if (!db) {\n    return;\n  }\n\n  try {\n    await db.put(`${DbReference.block}:${block.number}`, JSON.stringify(block));\n  } catch (error) {\n    throw new Error('`saveBlockDb` - Could not write to into the db - critical error!');\n  }\n};\n\n/**\n * Check if a signature has already been used before\n *\n * @param signature - The number of the block to get.\n */\nexport const hasSignatureBeenUsedBeforeDb = async (signature: string): Promise<boolean> => {\n  if (!db) {\n    return false;\n  }\n\n  try {\n    // if it does not throw its because it exists\n    await db.get(`${DbReference.tx_signature}:${signature}`);\n    return true;\n  } catch (e) {\n    return false;\n  }\n};\n\n/**\n * Saves a the signature submitted to the database.\n *\n * @param signature - The signature\n */\nconst saveSignatureDb = async (signature: string): Promise<void> => {\n  if (!db) {\n    return;\n  }\n\n  try {\n    await db.put(`${DbReference.tx_signature}:${signature}`, '');\n  } catch (error) {\n    throw new Error(\n      '`saveSignatureSubmittedDb` - Could not write to into the db - critical error!'\n    );\n  }\n};\n\n/**\n * Gets the last end cursor from the database.\n * Returns null if the database is not available or there is no cursor.\n * @returns The last end cursor.\n */\nexport const getLastEndCursorDb = async (): Promise<string | null> => {\n  invariant(db, 'Database not started');\n\n  try {\n    return await db.get(DbReference.cursor);\n  } catch (e) {\n    return null;\n  }\n};\n\n/**\n * Saves the end cursor to the database.\n * @param cursor - The end cursor to save.\n * @throws Throws an error if the database is not available.\n */\nexport const saveEndCursorDb = async (cursor: string): Promise<void> => {\n  invariant(db, 'Database not started');\n\n  try {\n    await db.put(DbReference.cursor, cursor);\n  } catch (error) {\n    throw new Error('Could not write to into the db - critical error!');\n  }\n};\n\n/**\n *  Gets the total checked count from the database.\n */\nexport const getTotalCheckedCountDb = async (): Promise<number> => {\n  invariant(db, 'Database not started');\n\n  try {\n    const result = await db.get(`${DbReference.tx}:totalCheckedCount`);\n    if (result) {\n      return Number(result);\n    }\n\n    return 0;\n  } catch (e) {\n    return 0;\n  }\n};\n\n/**\n *  Saves the total checked count to the database.\n * @param checked The checked count to add to current total\n */\nexport const saveTotalCheckedCountDb = async (checked: number): Promise<void> => {\n  invariant(db, 'Database not started');\n\n  try {\n    const currentCount = (await getTotalCheckedCountDb()) || 0;\n    await db.put(`${DbReference.tx}:totalCheckedCount`, (currentCount + checked).toString());\n  } catch (error) {\n    throw new Error('Could not write to into the db - critical error!');\n  }\n};\n\n/**\n * Saves the given publication metadata to the database under the given transaction ID\n * @param txId The transaction ID to use as the key in the database\n * @param publication The publication metadata to save\n * @throws An error if the database is not available or if the write operation fails\n */\nexport const saveTxDAMetadataDb = async (\n  txId: string,\n  publication: DAStructurePublication<DAEventType, PublicationTypedData>\n): Promise<void> => {\n  if (!db) {\n    return;\n  }\n\n  try {\n    await db.put(`${DbReference.tx_da_metadata}:${txId}`, JSON.stringify(publication));\n  } catch (error) {\n    throw new Error('Could not write to the db - critical error!');\n  }\n};\n\n/**\n * Retrieves the publication metadata associated with the given transaction ID from the database\n * @param txId The transaction ID to use as the key in the database\n * @returns The publication metadata if it is found, or null if it is not found or if the database is not available\n */\nexport const getTxDAMetadataDb = async (\n  txId: string\n): Promise<DAStructurePublication<DAEventType, PublicationTypedData> | null> => {\n  if (!db) {\n    return null;\n  }\n\n  try {\n    const result = await db.get(`${DbReference.tx_da_metadata}:${txId}`);\n    return JSON.parse(result) as DAStructurePublication<DAEventType, PublicationTypedData>;\n  } catch (e) {\n    return null;\n  }\n};\n\n/**\n * Saves the given timestamp proofs metadata to the database under the given transaction ID\n * @param txId The transaction ID to use as the key in the database\n * @param proofs The timestamp proofs metadata to save\n * @throws An error if the database is not available or if the write operation fails\n */\nexport const saveTxTimestampProofsMetadataDb = async (\n  txId: string,\n  proofs: DATimestampProofsResponse\n): Promise<void> => {\n  if (!db) {\n    return;\n  }\n\n  try {\n    await db.put(`${DbReference.tx_timestamp_proof_metadata}:${txId}`, JSON.stringify(proofs));\n  } catch (error) {\n    throw new Error('Could not write to the db - critical error!');\n  }\n};\n\n/**\n * Retrieves the timestamp proofs metadata associated with the given transaction ID from the database\n * @param txId The transaction ID to use as the key in the database\n * @returns The timestamp proofs metadata if it is found, or null if it is not found or if the database is not available\n */\nexport const getTxTimestampProofsMetadataDb = async (\n  txId: string\n): Promise<DATimestampProofsResponse | null> => {\n  if (!db) {\n    return null;\n  }\n\n  try {\n    const result = await db.get(`${DbReference.tx_timestamp_proof_metadata}:${txId}`);\n    return JSON.parse(result) as DATimestampProofsResponse;\n  } catch (e) {\n    return null;\n  }\n};\n"
  },
  {
    "path": "momoka-node/src/input-output/fetch-with-timeout.ts",
    "content": "export interface FetchProvider {\n  get: <TResponse>(url: string, options: { timeout: number }) => Promise<TResponse>;\n}\n\nexport const fetchWithTimeout = <TResponse>(\n  url: string,\n  { provider }: { provider: FetchProvider }\n): Promise<TResponse | null> => {\n  return provider.get<TResponse>(url, { timeout: 5000 });\n};\n"
  },
  {
    "path": "momoka-node/src/input-output/json-rpc-with-timeout.ts",
    "content": "import axios from 'axios';\nimport { JSONRPCMethods } from '../evm/jsonrpc-methods';\n\n// most RPC nodes rate limits is per second!\nexport const RATE_LIMIT_TIME = 1000;\n\nexport const JSONRPCWithTimeout = async <TResponse>(\n  url: string,\n  method: JSONRPCMethods,\n  params: unknown[],\n  returnErrorData = false\n): Promise<TResponse> => {\n  const request = {\n    id: 0,\n    jsonrpc: '2.0',\n    method,\n    params,\n  };\n\n  const response = await axios.post(url, JSON.stringify(request), {\n    timeout: 5000,\n  });\n\n  if (returnErrorData && response.data.error) {\n    return response.data.error.data as TResponse;\n  }\n\n  return response.data.result as TResponse;\n};\n"
  },
  {
    "path": "momoka-node/src/input-output/lib-curl-provider.ts",
    "content": "// import { curly } from 'node-libcurl';\n// import { FetchProvider } from './fetch-with-timeout';\n\n// export class LibCurlProvider implements FetchProvider {\n//   async get<TResponse>(url: string, { timeout }: { timeout: number }): Promise<TResponse> {\n//     const { statusCode, data } = await curly.get(url, {\n//       httpHeader: ['Content-Type: application/json'],\n//       curlyResponseBodyParser: false,\n//       followLocation: true,\n//       timeout,\n//     });\n\n//     if (statusCode !== 200) {\n//       throw new Error(`Failed to fetch ${url}`);\n//     }\n\n//     return JSON.parse(data.toString()) as TResponse;\n//   }\n// }\n"
  },
  {
    "path": "momoka-node/src/input-output/paths.ts",
    "content": "export type PathType = {\n  join(...paths: string[]): string;\n};\nlet _path: PathType | undefined;\nexport const pathResolver = async (): Promise<PathType> => {\n  if (_path) return Promise.resolve(_path);\n\n  const pathImport = await import('path');\n\n  return (_path = pathImport);\n};\n\nlet lensDAPathCache: string | undefined;\nexport const lensDAPath = async (): Promise<string> => {\n  if (lensDAPathCache) return Promise.resolve(lensDAPathCache);\n\n  const path = await pathResolver();\n  const result = path.join(process.cwd(), 'lens__da');\n  return (lensDAPathCache = result);\n};\n\nlet failedProofsPathCache: string | undefined;\nexport const failedProofsPath = async (): Promise<string> => {\n  if (failedProofsPathCache) return Promise.resolve(failedProofsPathCache);\n\n  const path = await pathResolver();\n  const result = path.join(process.cwd(), 'lens__da', 'failed-proofs');\n  return (failedProofsPathCache = result);\n};\n"
  },
  {
    "path": "momoka-node/src/input-output/post-with-timeout.ts",
    "content": "import axios from 'axios';\n\nexport const postWithTimeout = async <TResponse, TBody>(\n  url: string,\n  body: TBody\n): Promise<TResponse> => {\n  const { status, data } = await axios.post(url, body, {\n    headers: {\n      'Content-Type': 'application/json',\n    },\n    timeout: 5000,\n  });\n\n  if (status !== 200) {\n    throw new Error(`postWithTimeout: ${status} - ${data.toString()}`);\n  }\n\n  return data as TResponse;\n};\n"
  },
  {
    "path": "momoka-node/src/input-output/tx-validated-results.ts",
    "content": "import {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../data-availability-models/publications/data-availability-structure-publication';\nimport { MomokaValidatorError } from '../data-availability-models/validator-errors';\n\nexport type TxValidatedResult = TxValidatedFailureResult | TxValidatedSuccessResult;\n\ninterface TxValidatedResultBase<TSuccess extends boolean, TDAStructurePublication> {\n  proofTxId: string;\n  success: TSuccess;\n  dataAvailabilityResult: TDAStructurePublication;\n}\n\nexport interface TxValidatedFailureResult\n  extends TxValidatedResultBase<\n    false,\n    DAStructurePublication<DAEventType, PublicationTypedData> | undefined\n  > {\n  failureReason: MomokaValidatorError;\n  extraErrorInfo?: string;\n}\n\n// eslint-disable-next-line @typescript-eslint/no-empty-interface\nexport interface TxValidatedSuccessResult\n  extends TxValidatedResultBase<true, DAStructurePublication<DAEventType, PublicationTypedData>> {}\n"
  },
  {
    "path": "momoka-node/src/proofs/check-da-proof.ts",
    "content": "import { EthereumNode } from '../evm/ethereum';\nimport {\n  CheckDASubmissionOptions,\n  getDefaultCheckDASubmissionOptions,\n} from './models/check-da-submisson-options';\nimport { PromiseWithContextResult } from '../data-availability-models/da-result';\nimport {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../data-availability-models/publications/data-availability-structure-publication';\nimport { DaProofVerifier } from './da-proof-verifier';\nimport { DaProofChecker } from './da-proof-checker';\nimport { DAPublicationWithTimestampProofsBatchResult } from '../data-availability-models/data-availability-timestamp-proofs';\nimport { DaProofGateway } from './da-proof-gateway';\n\nconst gateway = new DaProofGateway();\nconst verifier = new DaProofVerifier();\nconst checker = new DaProofChecker(verifier, gateway);\n\n/**\n * Validates a data availability proof of a given transaction on the Arweave network, including the timestamp proofs.\n * @param txId The transaction ID to check.\n * @param ethereumNode The Ethereum node to use to validate the data availability proof.\n * @param options The options for validating the data availability proof.\n * @returns A `Promise` that resolves to a `PromiseResult` containing the validated data availability proof, or `void` if the validation fails.\n */\nexport const checkDAProof = (\n  txId: string,\n  ethereumNode: EthereumNode,\n  options: CheckDASubmissionOptions = getDefaultCheckDASubmissionOptions\n): PromiseWithContextResult<\n  DAStructurePublication<DAEventType, PublicationTypedData> | void,\n  DAStructurePublication<DAEventType, PublicationTypedData>\n> => {\n  return checker.checkDAProof(txId, ethereumNode, options);\n};\n\n/**\n * Checks a data availability proof with metadata, including the timestamp proofs and transaction ID.\n * If the proof has already been checked, returns the previous result.\n * If the submitter is invalid, returns an error.\n * Otherwise, runs the internal proof check and returns the result.\n * @param txId The transaction ID associated with the proof.\n * @param daPublicationWithTimestampProofs The data availability publication with associated timestamp proofs.\n * @param ethereumNode The Ethereum node to use for validation.\n * @param options Optional options for the check, including logging and pointer verification.\n * @returns A context result with the validated publication, or an error if validation fails.\n */\nexport const checkDAProofWithMetadata = (\n  txId: string,\n  daPublicationWithTimestampProofs: DAPublicationWithTimestampProofsBatchResult,\n  ethereumNode: EthereumNode,\n  options: CheckDASubmissionOptions = getDefaultCheckDASubmissionOptions\n): PromiseWithContextResult<\n  DAStructurePublication<DAEventType, PublicationTypedData>,\n  DAStructurePublication<DAEventType, PublicationTypedData>\n> => {\n  return checker.checkDAProofWithMetadata(\n    txId,\n    daPublicationWithTimestampProofs,\n    ethereumNode,\n    options\n  );\n};\n"
  },
  {
    "path": "momoka-node/src/proofs/check-da-proofs-batch.ts",
    "content": "import { Promise as BluebirdPromise } from 'bluebird';\nimport {\n  base64StringToJson,\n  chunkArray,\n  createTimeoutPromise,\n  formatDate,\n  unixTimestampToMilliseconds,\n} from '../common/helpers';\nimport { LoggerLevelColours, consoleDynamic } from '../common/logger';\nimport { DAResult } from '../data-availability-models/da-result';\nimport {\n  DAPublicationWithTimestampProofsBatchResult,\n  DATimestampProofsResponse,\n} from '../data-availability-models/data-availability-timestamp-proofs';\nimport {\n  DAEventType,\n  DAPublicationsBatchResult,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../data-availability-models/publications/data-availability-structure-publication';\nimport { MomokaValidatorError } from '../data-availability-models/validator-errors';\nimport { anvilForkFrom, getAnvilCurrentBlockNumber } from '../evm/anvil';\nimport { EthereumNode } from '../evm/ethereum';\nimport {\n  BundlrBulkTxSuccess,\n  BundlrBulkTxsResponse,\n  getBundlrBulkTxsAPI,\n} from '../input-output/bundlr/get-bundlr-bulk-txs.api';\nimport { TIMEOUT_ERROR } from '../input-output/common';\nimport { saveTxDAMetadataDb, saveTxDb, saveTxTimestampProofsMetadataDb } from '../input-output/db';\nimport { TxValidatedResult } from '../input-output/tx-validated-results';\nimport { failedDAProofQueue } from '../queue/known.queue';\nimport { shouldRetry } from '../queue/process-retry-check-da-proofs.queue';\nimport { invariant } from '../utils/invariant';\nimport { StreamCallback } from '../watchers/models/stream.type';\nimport { checkDAProofWithMetadata } from './check-da-proof';\nimport { getDefaultCheckDASubmissionOptions } from './models/check-da-submisson-options';\n\n/**\n * Builds a validation result object for a transaction ID and a data availability verification result.\n * @param txId - The ID of the transaction to validate.\n * @param result - The result of verifying data availability on-chain.\n * @returns A `TxValidatedResult` object indicating whether the verification was successful or not, along with relevant data.\n */\nconst buildTxValidationResult = (\n  txId: string,\n  result: DAResult<\n    DAStructurePublication<DAEventType, PublicationTypedData>,\n    DAStructurePublication<DAEventType, PublicationTypedData>\n  >\n): TxValidatedResult => {\n  if (result.isSuccess()) {\n    return {\n      proofTxId: txId,\n      success: true,\n      dataAvailabilityResult: result.successResult,\n    };\n  }\n\n  return {\n    proofTxId: txId,\n    success: false,\n    failureReason: result.failure,\n    dataAvailabilityResult: result.context,\n  };\n};\n\n/**\n * Builds an array of DAPublicationsBatchResult objects from an array of BundlrBulkTxSuccess objects.\n * Also saves the transaction metadata to the database.\n * @param results - The array of BundlrBulkTxSuccess objects to process.\n * @returns An array of DAPublicationsBatchResult objects.\n *          turned into a promise as base64StringToJson is CPU intensive.\n */\nexport const buildDAPublicationsBatchResult = async (\n  results: BundlrBulkTxSuccess[]\n): Promise<DAPublicationsBatchResult[]> => {\n  const batchResult = await Promise.all(\n    // eslint-disable-next-line require-await\n    results.map(async (result) => {\n      const daPublication = base64StringToJson(result.data) as DAStructurePublication<\n        DAEventType,\n        PublicationTypedData\n      >;\n      saveTxDAMetadataDb(result.id, daPublication);\n\n      return {\n        id: result.id,\n        daPublication,\n        submitter: result.address,\n      };\n    })\n  );\n\n  return Promise.resolve(batchResult);\n};\n\n/**\n * Builds an array of DAPublicationWithTimestampProofsBatchResult objects based on the results of multiple bundled transactions.\n * @param results The array of BundlrBulkTxSuccess objects to process.\n * @param daPublications The array of DAPublicationsBatchResult objects corresponding to the original set of transactions.\n * @returns An array of DAPublicationWithTimestampProofsBatchResult objects with timestamp proofs included.\n *          turned into a promise as base64StringToJson can be blocking\n */\nconst buildDAPublicationsWithTimestampProofsBatchResult = (\n  results: BundlrBulkTxSuccess[],\n  daPublications: DAPublicationsBatchResult[]\n): Promise<DAPublicationWithTimestampProofsBatchResult[]> => {\n  return Promise.all(\n    // eslint-disable-next-line require-await\n    results.map(async (result, i) => {\n      const timestampProofsData = base64StringToJson(result.data) as DATimestampProofsResponse;\n\n      saveTxTimestampProofsMetadataDb(result.id, timestampProofsData);\n\n      return {\n        ...daPublications[i],\n        submitter: result.address,\n        timestampProofsData,\n      };\n    })\n  );\n};\n\n/**\n *  Checks the data availability proofs for a batch of transactions.\n * @param txIds The array of transaction IDs to check.\n */\nconst getBundlrBulkTxs = async (txIds: string[]): Promise<BundlrBulkTxsResponse> => {\n  // can only handle 1000 at a time!\n  const txIdsChunks = chunkArray(txIds, 1000);\n\n  const bulkDAProofs = await Promise.all(\n    txIdsChunks.map(async (txIdsChunk) => {\n      const result = await getBundlrBulkTxsAPI(txIdsChunk);\n      if (result === TIMEOUT_ERROR) {\n        throw new Error('getBundlrBulkTxsAPI for proofs timed out');\n      }\n      return result;\n    })\n  );\n\n  const combinedResponse: BundlrBulkTxsResponse = bulkDAProofs.reduce(\n    (acc: BundlrBulkTxsResponse, current: BundlrBulkTxsResponse) => {\n      return {\n        success: [...acc.success, ...current.success],\n        failed: { ...acc.failed, ...current.failed },\n      };\n    },\n    {\n      success: [],\n      failed: {},\n    }\n  );\n\n  return combinedResponse;\n};\n\nexport interface ProofResult {\n  txId: string;\n  success: boolean;\n  validatorError?: MomokaValidatorError;\n}\n\n/**\n *  Checks the data availability proof for a publication\n * @param publication The publication to check\n * @param ethereumNode The ethereum node information\n * @param retryAttempt If its a retry\n * @param stream The callback to stream the result\n */\nconst processPublication = async (\n  publication: DAPublicationWithTimestampProofsBatchResult,\n  ethereumNode: EthereumNode,\n  retryAttempt: boolean,\n  stream?: StreamCallback\n): Promise<ProofResult> => {\n  const txId = publication.id;\n\n  try {\n    const checkPromise = checkDAProofWithMetadata(txId, publication, ethereumNode, {\n      ...getDefaultCheckDASubmissionOptions,\n      byPassDb: retryAttempt,\n    });\n\n    const { promise: timeoutPromise, timeoutId } = createTimeoutPromise(5000);\n    const result = await Promise.race([checkPromise, timeoutPromise]);\n\n    clearTimeout(timeoutId);\n\n    // TODO: In case of timeout, what would be the best course of action here? Just throw?\n    invariant(result, 'Publication process request timed out');\n\n    const txValidatedResult: TxValidatedResult = buildTxValidationResult(txId, result);\n\n    void saveTxDb(txId, txValidatedResult);\n\n    if (stream) {\n      // stream the result to the callback defined\n      stream(txValidatedResult);\n    }\n\n    return {\n      txId,\n      success: result.isSuccess(),\n      validatorError: result.isFailure() ? result.failure : undefined,\n    };\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  } catch (e: any) {\n    // console.log(`FAILED - ${e.message || e}`);\n    saveTxDb(txId, {\n      proofTxId: txId,\n      success: false,\n      failureReason: MomokaValidatorError.UNKNOWN,\n      dataAvailabilityResult: undefined,\n      extraErrorInfo: typeof e === 'string' ? e : e.message || undefined,\n    });\n\n    return {\n      txId,\n      success: false,\n      validatorError: MomokaValidatorError.UNKNOWN,\n    };\n  }\n};\n\n/**\n *  Checks the data availability proofs for a set of publications\n * @param publications The publications to check\n * @param ethereumNode The ethereum node information\n * @param retryAttempt If its a retry\n * @param concurrency The concurrency to use < this is how many TCP it will run at\n * @param stream The callback to stream the result\n */\nconst processPublications = (\n  publications: DAPublicationWithTimestampProofsBatchResult[],\n  ethereumNode: EthereumNode,\n  retryAttempt: boolean,\n  concurrency: number,\n  stream?: StreamCallback\n): Promise<ProofResult[]> => {\n  return BluebirdPromise.map(\n    publications,\n    async (publication) => {\n      const log = (\n        color: LoggerLevelColours,\n        message: string,\n        ...optionalParams: unknown[]\n      ): void => {\n        consoleDynamic(\n          color,\n          `LENS VERIFICATION NODE - ${retryAttempt ? 'retry attempt' : ''} tx at - ${formatDate(\n            new Date(unixTimestampToMilliseconds(Number(publication.daPublication.event.timestamp)))\n          )} - ${publication.id} - ${message}`,\n          ...optionalParams\n        );\n      };\n\n      const result = await processPublication(publication, ethereumNode, retryAttempt, stream);\n\n      if (result.success) {\n        log(LoggerLevelColours.SUCCESS, 'OK');\n      } else {\n        failedDAProofQueue.enqueue({\n          txId: result.txId,\n          reason: result.validatorError!,\n          submitter: publication.submitter,\n        });\n\n        const retriable = shouldRetry(result.validatorError!);\n\n        log(\n          LoggerLevelColours.ERROR,\n          `FAILED ${retriable ? '(RETRIABLE)' : ''} - ${result.validatorError!}`\n        );\n      }\n\n      return result;\n    },\n    // this is how we get more TCP but the higher we go\n    // the more requirements we need to set on the archive node to handle the load\n    // up to the running of node\n    { concurrency }\n  );\n};\n\n/**\n * Checks the data availability proofs and their corresponding timestamp proofs for a batch of DA submissions.\n * Saves the validation result for each submission to the database and optionally streams the result to a provided callback.\n * @param txIds - The data availability submissions to tx ids to check.\n * @param ethereumNode - The Ethereum node to use for verification.\n * @param retryAttempt If its a retry\n * @param concurrency The concurrency to use < this is how many TCP it will run at\n * @param stream - An optional callback function to stream the validation results.\n */\nexport const checkDAProofsBatch = async (\n  txIds: string[],\n  ethereumNode: EthereumNode,\n  retryAttempt: boolean,\n  concurrency: number,\n  usLocalNode = false,\n  stream?: StreamCallback\n): Promise<ProofResult[]> => {\n  // Get bulk data availability proofs.\n  const bulkDAProofs = await getBundlrBulkTxs(txIds);\n\n  // Build the data availability publication result for each submission.\n  const daPublications = await buildDAPublicationsBatchResult(bulkDAProofs.success);\n\n  if (usLocalNode) {\n    const mostRecentBlockNumber = Math.max(\n      ...daPublications.map((d) => d.daPublication.chainProofs.thisPublication.blockNumber)\n    );\n\n    const anvilCurrentBlockNumber = await getAnvilCurrentBlockNumber();\n\n    if (mostRecentBlockNumber > anvilCurrentBlockNumber) {\n      await anvilForkFrom(ethereumNode, mostRecentBlockNumber);\n    }\n  }\n\n  // Get bulk timestamp proofs.\n  const bulkDATimestampProofs = await getBundlrBulkTxs(\n    daPublications.map((pub) => pub.daPublication.timestampProofs.response.id)\n  );\n\n  // Build the data availability publication result with timestamp proofs for each submission.\n  const daPublicationsWithTimestampProofs = await buildDAPublicationsWithTimestampProofsBatchResult(\n    bulkDATimestampProofs.success,\n    daPublications\n  );\n\n  return processPublications(\n    daPublicationsWithTimestampProofs,\n    ethereumNode,\n    retryAttempt,\n    concurrency,\n    stream\n  );\n};\n"
  },
  {
    "path": "momoka-node/src/proofs/da-proof-checker.ts",
    "content": "import { Deployment, Environment } from '../common/environment';\nimport { LogFunctionType } from '../common/logger';\nimport {\n  PromiseResult,\n  PromiseWithContextResult,\n  PromiseWithContextResultOrNull,\n  failure,\n  failureWithContext,\n  success,\n} from '../data-availability-models/da-result';\nimport { MomokaActionTypes } from '../data-availability-models/data-availability-action-types';\nimport {\n  DAPublicationWithTimestampProofsBatchResult,\n  DATimestampProofsResponse,\n} from '../data-availability-models/data-availability-timestamp-proofs';\nimport { DAStructurePublication } from '../data-availability-models/publications/data-availability-structure-publication';\nimport { MomokaValidatorError } from '../data-availability-models/validator-errors';\nimport { BlockInfo, EthereumNode } from '../evm/ethereum';\nimport { TIMEOUT_ERROR, TimeoutError } from '../input-output/common';\nimport { TxValidatedFailureResult, TxValidatedResult } from '../input-output/tx-validated-results';\nimport { isValidSubmitter } from '../submitters';\nimport {\n  CheckDASubmissionOptions,\n  getDefaultCheckDASubmissionOptions,\n} from './models/check-da-submisson-options';\nimport { checkDAComment } from './publications/comment';\nimport { checkDAMirror } from './publications/mirror';\nimport { checkDAPost } from './publications/post';\nimport { getClosestBlock, isValidEventTimestamp, isValidTypedDataDeadlineTimestamp } from './utils';\nimport { createDAPublicationVerifier } from './publications/create-da-publication-verifier';\nimport { checkDAQuote } from './publications/quote';\n\nconst validResult = 'valid';\ntype ValidType = typeof validResult;\n\nexport interface DAProofsVerifier {\n  extractAddress(daPublication: DAStructurePublication): Promise<string>;\n\n  /**\n   * Check if bundlr timestamp proofs are valid and verified against bundlr node\n   */\n  verifyTimestampSignature(daPublication: DAStructurePublication): Promise<boolean>;\n\n  /**\n   * Checks if the given Arweave transaction was submitted by a valid submitter for the specified environment.\n   * @param environment The environment to check against.\n   * @param txId The Arweave transaction ID to check the submitter of.\n   * @param log A logging function to use for outputting log messages.\n   * @param deployment The deployment to check against.\n   * @returns A Promise that resolves to true if the submitter is valid, false if it is not valid, or a TimeoutError if the request timed out.\n   */\n  verifyTransactionSubmitter(\n    environment: Environment,\n    txId: string,\n    log: LogFunctionType,\n    deployment?: Deployment\n  ): Promise<boolean | TimeoutError>;\n}\n\nexport interface DAProofsGateway {\n  getTxResultFromCache(txId: string): Promise<TxValidatedResult | null>;\n  getDaPublication(txId: string): Promise<DAStructurePublication | TimeoutError | null>;\n  getTimestampProofs(\n    timestampId: string,\n    txId: string\n  ): Promise<DATimestampProofsResponse | TimeoutError | null>;\n  getBlockRange(blockNumbers: number[], ethereumNode: EthereumNode): Promise<BlockInfo[]>;\n  hasSignatureBeenUsedBefore(signature: string): Promise<boolean>;\n}\n\nexport class DaProofChecker {\n  constructor(private verifier: DAProofsVerifier, private gateway: DAProofsGateway) {}\n\n  /**\n   * Checks a data availability proof with metadata, including the timestamp proofs and transaction ID.\n   * If the proof has already been checked, returns the previous result.\n   * If the submitter is invalid, returns an error.\n   * Otherwise, runs the internal proof check and returns the result.\n   * @param txId The transaction ID associated with the proof.\n   * @param daPublicationWithTimestampProofs The data availability publication with associated timestamp proofs.\n   * @param ethereumNode The Ethereum node to use for validation.\n   * @param options Optional options for the check, including logging and pointer verification.\n   * @returns A context result with the validated publication, or an error if validation fails.\n   */\n\n  public checkDAProofWithMetadata = async (\n    txId: string,\n    daPublicationWithTimestampProofs: DAPublicationWithTimestampProofsBatchResult,\n    ethereumNode: EthereumNode,\n    options: CheckDASubmissionOptions = getDefaultCheckDASubmissionOptions\n  ): PromiseWithContextResult<DAStructurePublication, DAStructurePublication> => {\n    if (!options.byPassDb) {\n      const alreadyChecked = await this.txAlreadyChecked(txId, options.log);\n      if (alreadyChecked) {\n        return alreadyChecked;\n      }\n\n      const signatureAlreadyUsed = await this.gateway.hasSignatureBeenUsedBefore(\n        daPublicationWithTimestampProofs.daPublication.chainProofs.thisPublication.signature\n      );\n      if (signatureAlreadyUsed) {\n        return failureWithContext(\n          MomokaValidatorError.CHAIN_SIGNATURE_ALREADY_USED,\n          daPublicationWithTimestampProofs.daPublication\n        );\n      }\n    }\n\n    if (\n      !isValidSubmitter(\n        ethereumNode.environment,\n        daPublicationWithTimestampProofs.submitter,\n        ethereumNode.deployment\n      )\n    ) {\n      return failureWithContext(\n        MomokaValidatorError.TIMESTAMP_PROOF_NOT_SUBMITTER,\n        daPublicationWithTimestampProofs.daPublication\n      );\n    }\n\n    return await this._checkDAProof(\n      daPublicationWithTimestampProofs.daPublication,\n      daPublicationWithTimestampProofs.timestampProofsData,\n      ethereumNode,\n      options\n    );\n  };\n\n  /**\n   * Validates a data availability proof of a given transaction on the Arweave network, including the timestamp proofs.\n   * @param txId The transaction ID to check.\n   * @param ethereumNode The Ethereum node to use to validate the data availability proof.\n   * @param options The options for validating the data availability proof.\n   * @returns A `Promise` that resolves to a `PromiseResult` containing the validated data availability proof, or `void` if the validation fails.\n   */\n  public checkDAProof = async (\n    txId: string,\n    ethereumNode: EthereumNode,\n    options: CheckDASubmissionOptions = getDefaultCheckDASubmissionOptions\n  ): PromiseWithContextResult<DAStructurePublication | void, DAStructurePublication> => {\n    if (!options.byPassDb) {\n      const alreadyChecked = await this.txAlreadyChecked(txId, options.log);\n      if (alreadyChecked) {\n        return alreadyChecked;\n      }\n    }\n\n    txId = txId.replace('ar://', ''); // pointers have the ar prefix!\n\n    options.log(`Checking the submission`);\n\n    const daPublication = await this.gateway.getDaPublication(txId);\n\n    if (!daPublication) {\n      return failureWithContext(MomokaValidatorError.INVALID_TX_ID, undefined as any);\n    }\n    if (daPublication === TIMEOUT_ERROR) {\n      return failureWithContext(MomokaValidatorError.CAN_NOT_CONNECT_TO_BUNDLR, undefined as any);\n    }\n\n    const timestampProofsPayload = await this.gateway.getTimestampProofs(\n      daPublication.timestampProofs.response.id,\n      txId\n    );\n\n    if (!timestampProofsPayload) {\n      return failureWithContext(MomokaValidatorError.INVALID_TX_ID, undefined as any);\n    }\n    if (timestampProofsPayload === TIMEOUT_ERROR) {\n      return failureWithContext(MomokaValidatorError.CAN_NOT_CONNECT_TO_BUNDLR, undefined as any);\n    }\n\n    const timestampProofsSubmitter = await this.verifier.verifyTransactionSubmitter(\n      ethereumNode.environment,\n      daPublication.timestampProofs.response.id,\n      options.log,\n      ethereumNode.deployment\n    );\n    if (timestampProofsSubmitter === TIMEOUT_ERROR) {\n      return failureWithContext(MomokaValidatorError.CAN_NOT_CONNECT_TO_BUNDLR, undefined as any);\n    }\n    if (!timestampProofsSubmitter) {\n      return failureWithContext(MomokaValidatorError.TIMESTAMP_PROOF_NOT_SUBMITTER, daPublication);\n    }\n    options.log('timestamp proof valid submitter');\n\n    return await this._checkDAProof(daPublication, timestampProofsPayload, ethereumNode, options);\n  };\n\n  /**\n   * Validates the timestamp proofs and signatures of a given publication\n   * against the timestampProofs and ethereumNode parameters.\n   * @param daPublication The publication to validate.\n   * @param timestampProofs The timestamp proofs to validate the publication against.\n   * @param ethereumNode The Ethereum node to validate the publication against.\n   * @param options The optional parameters to use when checking the publication.\n   * @returns A promise with the result of the validation.\n   */\n  private _checkDAProof = async (\n    daPublication: DAStructurePublication,\n    timestampProofs: DATimestampProofsResponse,\n    ethereumNode: EthereumNode,\n    { log, byPassDb, verifyPointer }: CheckDASubmissionOptions\n  ): PromiseWithContextResult<DAStructurePublication, DAStructurePublication> => {\n    if (!daPublication.signature) {\n      return failureWithContext(MomokaValidatorError.NO_SIGNATURE_SUBMITTER, daPublication);\n    }\n\n    if (!(await this.isValidSignatureSubmitter(daPublication, ethereumNode, log))) {\n      return failureWithContext(MomokaValidatorError.INVALID_SIGNATURE_SUBMITTER, daPublication);\n    }\n\n    const timestampProofsResult = await this.validatesTimestampProof(\n      daPublication,\n      timestampProofs,\n      log\n    );\n    if (timestampProofsResult !== validResult) {\n      return failureWithContext(timestampProofsResult, daPublication);\n    }\n\n    if (!isValidEventTimestamp(daPublication)) {\n      log('event timestamp does not match the publication timestamp');\n      // the event emitted must match the same timestamp as the block number\n      return failureWithContext(MomokaValidatorError.INVALID_EVENT_TIMESTAMP, daPublication);\n    }\n\n    if (!isValidTypedDataDeadlineTimestamp(daPublication)) {\n      log('typed data timestamp does not match the publication timestamp');\n      // the event emitted must match the same timestamp as the block number\n      return failureWithContext(\n        MomokaValidatorError.INVALID_TYPED_DATA_DEADLINE_TIMESTAMP,\n        daPublication\n      );\n    }\n\n    log('event timestamp matches publication timestamp');\n\n    const validateBlockResult = await this.validateChoosenBlock(\n      daPublication.chainProofs.thisPublication.blockNumber,\n      daPublication.timestampProofs.response.timestamp,\n      ethereumNode,\n      log\n    );\n\n    if (validateBlockResult.isFailure()) {\n      return failureWithContext(validateBlockResult.failure, daPublication);\n    }\n\n    log('event timestamp matches up the on chain block timestamp');\n\n    const daResult = await this.checkDAPublication(\n      daPublication,\n      ethereumNode,\n      {\n        log,\n        byPassDb,\n        verifyPointer,\n      },\n      log\n    );\n\n    if (daResult.isFailure()) {\n      return failureWithContext(daResult.failure, daPublication);\n    }\n\n    return success(daPublication);\n  };\n\n  /**\n   * Checks if the signature submitter is valid.\n   * @param daPublication - The publication to check.\n   * @param ethereumNode - The Ethereum node to use.\n   * @param log - The logging function to use.\n   * @returns True if the signature submitter is valid, false otherwise.\n   *          turned into a promise as its CPU intensive\n   */\n  private isValidSignatureSubmitter = async (\n    daPublication: DAStructurePublication,\n    ethereumNode: EthereumNode,\n    log: LogFunctionType\n  ): Promise<boolean> => {\n    const signedAddress = await this.verifier.extractAddress(daPublication);\n\n    log('signedAddress', signedAddress);\n\n    return isValidSubmitter(ethereumNode.environment, signedAddress, ethereumNode.deployment);\n  };\n\n  /**\n   * Validates the timestamp proof of the given DA publication against the corresponding timestamp proof payload.\n   * @param daPublication The DA publication to validate the timestamp proof of.\n   * @param timestampProofs The timestamp proof payload to validate the DA publication against.\n   * @param log A logging function to output debug information.\n   * @returns A Promise that resolves with a `ValidType` if the timestamp proof is valid or an error code if it is not.\n   */\n  private async validatesTimestampProof(\n    daPublication: DAStructurePublication,\n    timestampProofs: DATimestampProofsResponse,\n    log: LogFunctionType\n  ): Promise<\n    | MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SIGNATURE\n    | MomokaValidatorError.TIMESTAMP_PROOF_INVALID_TYPE\n    | MomokaValidatorError.TIMESTAMP_PROOF_INVALID_DA_ID\n    | ValidType\n    // eslint-disable-next-line require-await\n  > {\n    const valid = await this.verifier.verifyTimestampSignature(daPublication);\n\n    if (!valid) {\n      log('timestamp proof invalid signature');\n      return MomokaValidatorError.TIMESTAMP_PROOF_INVALID_SIGNATURE;\n    }\n\n    log('timestamp proof signature valid');\n\n    if (timestampProofs.type !== daPublication.type) {\n      log('timestamp proof type mismatch');\n      return MomokaValidatorError.TIMESTAMP_PROOF_INVALID_TYPE;\n    }\n\n    if (timestampProofs.dataAvailabilityId !== daPublication.dataAvailabilityId) {\n      log('timestamp proof da id mismatch');\n      return MomokaValidatorError.TIMESTAMP_PROOF_INVALID_DA_ID;\n    }\n\n    return validResult;\n  }\n\n  /**\n   * Retrieves block information for a range of block numbers.\n   * If a block has been retrieved previously, it will return the cached value instead of querying the network.\n   * Any newly retrieved blocks will be cached for future use.\n   * @param blockNumbers An array of block numbers to retrieve information for\n   * @param ethereumNode The Ethereum node to query for block information\n   * @returns A PromiseResult containing an array of BlockInfo objects, or a TimeoutError if the query times out\n   */\n  private async getBlockRange(\n    blockNumbers: number[],\n    ethereumNode: EthereumNode\n  ): PromiseResult<BlockInfo[]> {\n    try {\n      const blocks = await this.gateway.getBlockRange(blockNumbers, ethereumNode);\n\n      return success(blocks);\n    } catch (error) {\n      return failure(MomokaValidatorError.BLOCK_CANT_BE_READ_FROM_NODE);\n    }\n  }\n\n  /**\n   * Validate if a block number is the closest one to a given timestamp.\n   * @param blockNumber - The block number to be validated.\n   * @param timestamp - The timestamp to be used to validate the block.\n   * @param ethereumNode - The Ethereum node to be used for block validation.\n   * @param log - The log function used to log debug information.\n   * @returns A PromiseResult containing a success result if the block is validated, or a failure with the corresponding error.\n   */\n  private async validateChoosenBlock(\n    blockNumber: number,\n    timestamp: number,\n    ethereumNode: EthereumNode,\n    log: LogFunctionType\n  ): PromiseResult {\n    try {\n      // got the current block, the previous block, and the block in the future!\n      const blockNumbers = [blockNumber - 1, blockNumber, blockNumber + 1];\n\n      const blocksResult = await this.getBlockRange(blockNumbers, ethereumNode);\n\n      if (blocksResult.isFailure()) {\n        return failure(blocksResult.failure);\n      }\n\n      const blocks = blocksResult.successResult;\n      log(\n        'blocks',\n        blocks.map((c) => ({ time: c.timestamp * 1000, blockNumber: c.number }))\n      );\n      log('timestamp', timestamp);\n\n      const closestBlock = getClosestBlock(blocks, timestamp);\n\n      // compare block numbers to make sure they are the same\n      if (closestBlock.number !== blockNumber) {\n        log('closestBlock does not match', {\n          closestBlock: closestBlock.number,\n          submittedBlockNumber: blockNumber,\n          closestBlockFull: closestBlock,\n        });\n\n        if (closestBlock.number === blockNumber + 1) {\n          log(\n            `\n        Due to latency with nodes, we allow the next block to be accepted as the closest.\n        When you do a request over the wire, the node provider may not have broadcasted yet,\n        this means you may have 100-300ms latency which cannot be avoided. The signature still\n        needs to conform to the past block, so it's still very valid.\n        `\n          );\n        } else {\n          return failure(MomokaValidatorError.NOT_CLOSEST_BLOCK);\n        }\n      }\n\n      log('compare done', { choosenBlock: closestBlock.timestamp, timestamp });\n\n      //TODO look at this again\n      // block times are 2 seconds so this should never ever happen\n      // if (closestBlock.number + 2500 > timestamp) {\n      //   throw new Error(MomokaValidatorError.BLOCK_TOO_FAR);\n      // }\n\n      return success();\n    } catch (e) {\n      log('validateChoosenBlock error', e);\n      return failure(MomokaValidatorError.UNKNOWN);\n    }\n  }\n\n  /**\n   * Validates a publication of a DA structure by checking its type and calling the appropriate check function.\n   * @param daPublication The publication to validate.\n   * @param ethereumNode The Ethereum node to use for validation.\n   * @param checkOptions Options for checking the publication.\n   * @param log A logging function to use for outputting log messages.\n   * @returns A PromiseResult indicating the success or failure of the publication check.\n   */\n  private async checkDAPublication(\n    daPublication: DAStructurePublication,\n    ethereumNode: EthereumNode,\n    checkOptions: CheckDASubmissionOptions,\n    log: LogFunctionType\n  ): PromiseResult {\n    const publicationVerifierResult = await createDAPublicationVerifier(\n      daPublication,\n      ethereumNode,\n      log\n    );\n\n    if (publicationVerifierResult.isFailure()) {\n      return failure(publicationVerifierResult.failure);\n    }\n\n    const publicationVerifier = publicationVerifierResult.successResult;\n\n    const publicationIdMatchesResult = await publicationVerifier.verifyPublicationIdMatches();\n\n    if (publicationIdMatchesResult.isFailure()) {\n      return failure(publicationIdMatchesResult.failure);\n    }\n\n    switch (publicationVerifier.type) {\n      case MomokaActionTypes.POST_CREATED:\n        return checkDAPost(publicationVerifier, checkOptions.log);\n      case MomokaActionTypes.COMMENT_CREATED:\n        return checkDAComment(\n          publicationVerifier,\n          checkOptions.verifyPointer,\n          ethereumNode,\n          checkOptions.log,\n          this\n        );\n      case MomokaActionTypes.MIRROR_CREATED:\n        return checkDAMirror(\n          publicationVerifier,\n          checkOptions.verifyPointer,\n          ethereumNode,\n          checkOptions.log,\n          this\n        );\n      case MomokaActionTypes.QUOTE_CREATED:\n        return checkDAQuote(\n          publicationVerifier,\n          checkOptions.verifyPointer,\n          ethereumNode,\n          checkOptions.log,\n          this\n        );\n      default:\n        return failure(MomokaValidatorError.PUBLICATION_NOT_RECOGNIZED);\n    }\n  }\n\n  /**\n   * Checks if the given transaction ID has already been checked and returns the corresponding publication.\n   * If the transaction ID is found in the database, returns either a success or failure result depending on whether the\n   * publication was validated successfully or not, respectively.\n   * If the transaction ID is not found in the database, returns null.\n   * @param txId The transaction ID to check\n   * @param log The logging function to use\n   * @returns A promise that resolves to a success or failure result if the publication has already been checked, or null otherwise.\n   */\n  private async txAlreadyChecked(\n    txId: string,\n    log: LogFunctionType\n  ): PromiseWithContextResultOrNull<DAStructurePublication, DAStructurePublication> {\n    // Check if the transaction ID exists in the database\n    const cacheResult = await this.gateway.getTxResultFromCache(txId);\n\n    if (cacheResult) {\n      // If the transaction ID is found, log a message and return the corresponding publication\n      log('Already checked submission');\n\n      if (cacheResult.success) {\n        return success(cacheResult.dataAvailabilityResult);\n      }\n\n      return failureWithContext(\n        (<TxValidatedFailureResult>cacheResult).failureReason,\n        cacheResult.dataAvailabilityResult!\n      );\n    }\n\n    // If the transaction ID is not found, return null\n    return null;\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/da-proof-gateway.ts",
    "content": "import { AxiosProvider } from '../client/axios-provider';\nimport { DATimestampProofsResponse } from '../data-availability-models/data-availability-timestamp-proofs';\nimport {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../data-availability-models/publications/data-availability-structure-publication';\nimport { BlockInfo, EthereumNode, getBlock } from '../evm/ethereum';\nimport { getBundlrByIdAPI } from '../input-output/bundlr/get-bundlr-by-id.api';\nimport { TimeoutError } from '../input-output/common';\nimport {\n  getBlockDb,\n  getTxDAMetadataDb,\n  getTxDb,\n  getTxTimestampProofsMetadataDb,\n  hasSignatureBeenUsedBeforeDb,\n  saveBlockDb,\n} from '../input-output/db';\nimport { TxValidatedResult } from '../input-output/tx-validated-results';\nimport { DAProofsGateway } from '../proofs/da-proof-checker';\n\nexport class DaProofGateway implements DAProofsGateway {\n  public hasSignatureBeenUsedBefore(signature: string): Promise<boolean> {\n    return hasSignatureBeenUsedBeforeDb(signature);\n  }\n\n  public getTxResultFromCache(txId: string): Promise<TxValidatedResult | null> {\n    // Check if the transaction ID exists in the database\n    return getTxDb(txId);\n  }\n\n  public getBlockRange(blockNumbers: number[], ethereumNode: EthereumNode): Promise<BlockInfo[]> {\n    return Promise.all(\n      blockNumbers.map(async (blockNumber) => {\n        const cachedBlock = await getBlockDb(blockNumber);\n        if (cachedBlock) {\n          return cachedBlock;\n        }\n\n        const block = await getBlock(blockNumber, ethereumNode);\n\n        // fire and forget!\n        saveBlockDb(block);\n\n        return block;\n      })\n    );\n  }\n\n  public async getDaPublication(\n    txId: string\n  ): Promise<DAStructurePublication<DAEventType, PublicationTypedData> | TimeoutError | null> {\n    return (\n      (await getTxDAMetadataDb(txId)) ||\n      (await getBundlrByIdAPI<DAStructurePublication<DAEventType, PublicationTypedData>>(txId, {\n        // use Axios for now as lib curl is causing some issues on different OS\n        provider: new AxiosProvider(),\n      }))\n    );\n  }\n\n  public async getTimestampProofs(\n    timestampId: string,\n    txId: string\n  ): Promise<DATimestampProofsResponse | TimeoutError | null> {\n    return (\n      (await getTxTimestampProofsMetadataDb(txId)) ||\n      (await getBundlrByIdAPI<DATimestampProofsResponse>(timestampId, {\n        // use Axios for now as lib curl is causing some issues on different OS\n        provider: new AxiosProvider(),\n      }))\n    );\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/da-proof-verifier.ts",
    "content": "import { AxiosProvider } from '../client/axios-provider';\nimport { Deployment, Environment } from '../common/environment';\nimport { deepClone } from '../common/helpers';\nimport { LogFunctionType } from '../common/logger';\nimport {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../data-availability-models/publications/data-availability-structure-publication';\nimport { getOwnerOfTransactionAPI } from '../input-output/bundlr/get-owner-of-transaction.api';\nimport { TIMEOUT_ERROR, TimeoutError } from '../input-output/common';\nimport { isValidSubmitter } from '../submitters';\nimport { HandlerWorkers } from '../workers/handler-communication.worker';\nimport { workerPool } from '../workers/worker-pool';\nimport { DAProofsVerifier } from './da-proof-checker';\n\nexport class DaProofVerifier implements DAProofsVerifier {\n  public extractAddress(\n    daPublication: DAStructurePublication<DAEventType, PublicationTypedData>\n  ): Promise<string> {\n    const signature = deepClone(daPublication.signature);\n\n    // eslint-disable-next-line @typescript-eslint/ban-ts-comment\n    // @ts-ignore\n    // TODO: Is that important to remove signature from the shared object?\n    delete daPublication.signature;\n\n    return workerPool.execute<string>({\n      worker: HandlerWorkers.EVM_VERIFY_MESSAGE,\n      data: {\n        daPublication,\n        signature,\n      },\n    });\n  }\n\n  public verifyTimestampSignature(\n    daPublication: DAStructurePublication<DAEventType, PublicationTypedData>\n  ): Promise<boolean> {\n    return workerPool.execute<boolean>({\n      worker: HandlerWorkers.BUNDLR_VERIFY_RECEIPT,\n      data: {\n        bundlrUploadResponse: daPublication.timestampProofs.response,\n      },\n    });\n  }\n\n  public async verifyTransactionSubmitter(\n    environment: Environment,\n    txId: string,\n    log: LogFunctionType,\n    deployment?: Deployment\n  ): Promise<boolean | TimeoutError> {\n    // use Axios for now as lib curl is causing some issues on different OS\n    const owner = await getOwnerOfTransactionAPI(txId, { provider: new AxiosProvider() });\n    if (owner === TIMEOUT_ERROR) {\n      return TIMEOUT_ERROR;\n    }\n\n    log('owner result', owner);\n    if (!owner) {\n      return false;\n    }\n\n    return isValidSubmitter(environment, owner, deployment);\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/models/check-da-submisson-options.ts",
    "content": "import { LogFunctionType } from '../../common/logger';\n\nexport interface CheckDASubmissionOptions {\n  verifyPointer: boolean;\n  byPassDb: boolean;\n  log: LogFunctionType;\n}\n\nexport const getDefaultCheckDASubmissionOptions: CheckDASubmissionOptions = {\n  // eslint-disable-next-line @typescript-eslint/no-empty-function\n  log: () => {},\n  byPassDb: false,\n  verifyPointer: true,\n};\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/comment/da-comment-verifier-v1.ts",
    "content": "import { DAStructurePublication } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DACommentCreatedEventEmittedResponseV1 } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { DAPublicationVerifierV1 } from '../da-publication-verifier-v1';\nimport { CreateCommentV1EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport { LogFunctionType } from '../../../common/logger';\nimport { failure, PromiseResult, success } from '../../../data-availability-models/da-result';\nimport { BigNumber } from 'ethers';\nimport { MomokaValidatorError } from '../../../data-availability-models/validator-errors';\nimport { EMPTY_BYTE, EthereumNode } from '../../../evm/ethereum';\nimport { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\n\nexport type DACommentPublicationV1 = DAStructurePublication<\n  DACommentCreatedEventEmittedResponseV1,\n  CreateCommentV1EIP712TypedData\n>;\n\nexport const isDACommentPublicationV1 = (\n  daPublication: DAStructurePublication\n): daPublication is DACommentPublicationV1 => {\n  return (\n    daPublication.type === MomokaActionTypes.COMMENT_CREATED &&\n    !('commentParams' in daPublication.event)\n  );\n};\n\nexport class DACommentVerifierV1 extends DAPublicationVerifierV1 {\n  public readonly type = MomokaActionTypes.COMMENT_CREATED;\n\n  constructor(\n    public readonly daPublication: DACommentPublicationV1,\n    ethereumNode: EthereumNode,\n    log: LogFunctionType\n  ) {\n    super(daPublication, ethereumNode, log);\n  }\n\n  public verifyEventWithTypedData(pubCountAtBlock: string): PromiseResult {\n    const event = this.daPublication.event;\n    const typedData = this.daPublication.chainProofs.thisPublication.typedData;\n\n    // compare all event emitted to typed data value\n    this.log('cross check event with typed data value');\n\n    // check the pub count makes sense from the block!\n    if (BigNumber.from(pubCountAtBlock).add(1).toHexString() !== event.pubId) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('pub count at block is correct');\n\n    // compare all others!\n    if (\n      typedData.value.profileId !== event.profileId ||\n      typedData.value.contentURI !== event.contentURI ||\n      typedData.value.profileIdPointed !== event.profileIdPointed ||\n      typedData.value.pubIdPointed !== event.pubIdPointed ||\n      typedData.value.collectModule !== event.collectModule ||\n      event.collectModuleReturnData !== EMPTY_BYTE ||\n      typedData.value.referenceModule !== event.referenceModule ||\n      event.referenceModuleReturnData !== EMPTY_BYTE ||\n      typedData.value.collectModuleInitData !== EMPTY_BYTE ||\n      typedData.value.referenceModuleInitData !== EMPTY_BYTE\n    ) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('cross check event is complete');\n\n    return Promise.resolve(success());\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/comment/da-comment-verifier-v2.ts",
    "content": "import { DAStructurePublication } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DACommentCreatedEventEmittedResponseV2 } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { CreateCommentV2EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport { LogFunctionType } from '../../../common/logger';\nimport { failure, PromiseResult, success } from '../../../data-availability-models/da-result';\nimport { BigNumber } from 'ethers';\nimport { MomokaValidatorError } from '../../../data-availability-models/validator-errors';\nimport { DAPublicationVerifierV2 } from '../da-publication-verifier-v2';\nimport { generatePublicationId } from '../../utils';\nimport { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { EMPTY_BYTE, EthereumNode } from '../../../evm/ethereum';\nimport { arraysEqual } from '../../../utils/arrays-equal';\n\nexport type DACommentPublicationV2 = DAStructurePublication<\n  DACommentCreatedEventEmittedResponseV2,\n  CreateCommentV2EIP712TypedData\n>;\n\nexport const isDACommentPublicationV2 = (\n  daPublication: DAStructurePublication\n): daPublication is DACommentPublicationV2 => {\n  return (\n    daPublication.type === MomokaActionTypes.COMMENT_CREATED &&\n    'commentParams' in daPublication.event\n  );\n};\n\nexport class DACommentVerifierV2 extends DAPublicationVerifierV2 {\n  public readonly type = MomokaActionTypes.COMMENT_CREATED;\n\n  constructor(\n    public readonly daPublication: DACommentPublicationV2,\n    ethereumNode: EthereumNode,\n    log: LogFunctionType\n  ) {\n    super(daPublication, ethereumNode, log);\n  }\n\n  verifyPublicationIdMatches(): PromiseResult {\n    const generatedPublicationId = generatePublicationId(\n      this.daPublication.event.commentParams.profileId,\n      this.daPublication.event.pubId,\n      this.daPublication.dataAvailabilityId\n    );\n\n    if (generatedPublicationId !== this.daPublication.publicationId) {\n      this.log('publicationId does not match the generated one');\n\n      return Promise.resolve(failure(MomokaValidatorError.GENERATED_PUBLICATION_ID_MISMATCH));\n    }\n\n    return Promise.resolve(success());\n  }\n\n  verifyEventWithTypedData(pubCountAtBlock: string): PromiseResult {\n    const event = this.daPublication.event;\n    const typedData = this.daPublication.chainProofs.thisPublication.typedData;\n\n    // compare all event emitted to typed data value\n    this.log('cross check event with typed data value');\n\n    // check the pub count makes sense from the block!\n    if (BigNumber.from(pubCountAtBlock).add(1).toHexString() !== event.pubId) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('pub count at block is correct');\n\n    // compare all others!\n    if (\n      typedData.value.profileId !== event.commentParams.profileId ||\n      typedData.value.contentURI !== event.commentParams.contentURI ||\n      typedData.value.pointedProfileId !== event.commentParams.pointedProfileId ||\n      typedData.value.pointedPubId !== event.commentParams.pointedPubId ||\n      !arraysEqual(typedData.value.actionModules, event.commentParams.actionModules) ||\n      !arraysEqual(\n        typedData.value.actionModulesInitDatas,\n        event.commentParams.actionModulesInitDatas\n      ) ||\n      typedData.value.referenceModule !== event.commentParams.referenceModule ||\n      typedData.value.referenceModuleInitData !== event.commentParams.referenceModuleInitData ||\n      !arraysEqual(typedData.value.referrerProfileIds, event.commentParams.referrerProfileIds) ||\n      !arraysEqual(typedData.value.referrerPubIds, event.commentParams.referrerPubIds) ||\n      event.actionModulesInitReturnDatas.length !== 0 ||\n      event.referenceModuleReturnData !== EMPTY_BYTE ||\n      event.referenceModuleInitReturnData !== EMPTY_BYTE\n    ) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('cross check event is complete');\n\n    return Promise.resolve(success());\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/comment/index.ts",
    "content": "import { LogFunctionType } from '../../../common/logger';\nimport { failure, PromiseResult } from '../../../data-availability-models/da-result';\nimport { DAPublicationPointerType } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { MomokaValidatorError } from '../../../data-availability-models/validator-errors';\nimport { EthereumNode } from '../../../evm/ethereum';\nimport { DaProofChecker } from '../../da-proof-checker';\nimport { DACommentVerifierV1 } from './da-comment-verifier-v1';\nimport { DACommentVerifierV2 } from './da-comment-verifier-v2';\n\n/**\n * Checks if the given DACommentPublication is valid by verifying the proof chain, cross-checking against the event, and\n * validating the signature.\n * @param daPublicationVerifier The verifier for the DACommentPublication.\n * @param verifyPointer If true, the pointer chain will be verified before checking the publication.\n * @param ethereumNode The EthereumNode to use for fetching data from the Ethereum blockchain.\n * @param log A function used for logging output.\n * @param checker The DAProofChecker to use for checking the proof.\n * @returns A PromiseResult indicating success or failure, along with an optional error message.\n */\nexport const checkDAComment = async (\n  daPublicationVerifier: DACommentVerifierV1 | DACommentVerifierV2,\n  verifyPointer: boolean,\n  ethereumNode: EthereumNode,\n  log: LogFunctionType,\n  checker: DaProofChecker\n): PromiseResult => {\n  log('check DA comment');\n\n  const publication = daPublicationVerifier.daPublication;\n\n  if (!publication.chainProofs.pointer) {\n    return failure(MomokaValidatorError.PUBLICATION_NO_POINTER);\n  }\n\n  if (publication.chainProofs.pointer.type !== DAPublicationPointerType.ON_DA) {\n    return failure(MomokaValidatorError.PUBLICATION_NONE_DA);\n  }\n\n  if (verifyPointer) {\n    log('verify pointer first');\n\n    // check the pointer!\n    const pointerResult = await checker.checkDAProof(\n      publication.chainProofs.pointer.location,\n      ethereumNode,\n      {\n        byPassDb: false,\n        verifyPointer: false,\n        log,\n      }\n    );\n    if (pointerResult.isFailure()) {\n      return failure(MomokaValidatorError.POINTER_FAILED_VERIFICATION);\n    }\n  }\n\n  const signerResult = await daPublicationVerifier.verifySigner();\n\n  if (signerResult.isFailure()) {\n    return failure(signerResult.failure);\n  }\n\n  const eventResult = await daPublicationVerifier.verifyEventWithTypedData(\n    signerResult.successResult.currentPublicationId\n  );\n\n  log('finished checking DA comment');\n\n  return eventResult;\n};\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/create-da-publication-verifier.ts",
    "content": "import { DAStructurePublication } from '../../data-availability-models/publications/data-availability-structure-publication';\nimport { MomokaActionTypes } from '../../data-availability-models/data-availability-action-types';\nimport { DACommentVerifierV1, isDACommentPublicationV1 } from './comment/da-comment-verifier-v1';\nimport { DACommentVerifierV2, isDACommentPublicationV2 } from './comment/da-comment-verifier-v2';\nimport { LogFunctionType } from '../../common/logger';\nimport { DAMirrorVerifierV1, isDAMirrorPublicationV1 } from './mirror/da-mirror-verifier-v1';\nimport { DAMirrorVerifierV2, isDAMirrorPublicationV2 } from './mirror/da-mirror-verifier-v2';\nimport { EthereumNode } from '../../evm/ethereum';\nimport { DAPostVerifierV1, isDAPostPublicationV1 } from './post/da-post-verifier-v1';\nimport { DAPostVerifierV2, isDAPostPublicationV2 } from './post/da-post-verifier-v2';\nimport { DAQuoteVerifierV2, isDAQuotePublicationV2 } from './quote/da-quote-verifier-v2';\nimport { failure, PromiseResult, success } from '../../data-availability-models/da-result';\nimport { MomokaValidatorError } from '../../data-availability-models/validator-errors';\n\nexport type DAPublicationVerifier =\n  | DAPostVerifierV1\n  | DAPostVerifierV2\n  | DACommentVerifierV1\n  | DACommentVerifierV2\n  | DAMirrorVerifierV1\n  | DAMirrorVerifierV2\n  | DAQuoteVerifierV2;\n\nexport const createDAPublicationVerifier = (\n  daPublication: DAStructurePublication,\n  ethereumNode: EthereumNode,\n  log: LogFunctionType\n): PromiseResult<DAPublicationVerifier> => {\n  switch (daPublication.type) {\n    case MomokaActionTypes.POST_CREATED:\n      if (isDAPostPublicationV1(daPublication)) {\n        log('verifying post v1');\n        return Promise.resolve(success(new DAPostVerifierV1(daPublication, ethereumNode, log)));\n      }\n\n      if (isDAPostPublicationV2(daPublication)) {\n        log('verifying post v2');\n\n        return Promise.resolve(success(new DAPostVerifierV2(daPublication, ethereumNode, log)));\n      }\n\n      log('post was not recognized as v1 or v2');\n\n      return Promise.resolve(failure(MomokaValidatorError.PUBLICATION_NOT_RECOGNIZED));\n    case MomokaActionTypes.COMMENT_CREATED:\n      if (isDACommentPublicationV1(daPublication)) {\n        log('verifying comment v1');\n\n        return Promise.resolve(success(new DACommentVerifierV1(daPublication, ethereumNode, log)));\n      }\n\n      if (isDACommentPublicationV2(daPublication)) {\n        log('verifying comment v2');\n\n        return Promise.resolve(success(new DACommentVerifierV2(daPublication, ethereumNode, log)));\n      }\n\n      log('comment was not recognized as v1 or v2');\n\n      return Promise.resolve(failure(MomokaValidatorError.PUBLICATION_NOT_RECOGNIZED));\n    case MomokaActionTypes.MIRROR_CREATED:\n      if (isDAMirrorPublicationV1(daPublication)) {\n        log('verifying mirror v1');\n\n        return Promise.resolve(success(new DAMirrorVerifierV1(daPublication, ethereumNode, log)));\n      }\n      if (isDAMirrorPublicationV2(daPublication)) {\n        log('verifying mirror v2');\n\n        return Promise.resolve(success(new DAMirrorVerifierV2(daPublication, ethereumNode, log)));\n      }\n\n      log('mirror was not recognized as v1 or v2');\n\n      return Promise.resolve(failure(MomokaValidatorError.PUBLICATION_NOT_RECOGNIZED));\n    case MomokaActionTypes.QUOTE_CREATED:\n      if (isDAQuotePublicationV2(daPublication)) {\n        log('verifying quote v2');\n\n        return Promise.resolve(success(new DAQuoteVerifierV2(daPublication, ethereumNode, log)));\n      }\n      log('quote was not recognized as v2');\n\n      return Promise.resolve(failure(MomokaValidatorError.PUBLICATION_NOT_RECOGNIZED));\n    default:\n      return Promise.resolve(failure(MomokaValidatorError.PUBLICATION_NOT_RECOGNIZED));\n  }\n};\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/da-publication-verifier-v1.ts",
    "content": "import { DAStructurePublication } from '../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAEventTypeV1 } from '../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { PublicationV1TypedData } from '../../data-availability-models/publications/data-availability-publication-typed-data';\nimport { generatePublicationId } from '../utils';\nimport { failure, PromiseResult, success } from '../../data-availability-models/da-result';\nimport { whoSignedTypedData } from './publication.base';\nimport { MomokaValidatorError } from '../../data-availability-models/validator-errors';\nimport { LensHubV1Gateway } from '../../evm/gateway/LensHubV1Gateway';\nimport { EthereumNode } from '../../evm/ethereum';\nimport { LogFunctionType } from '../../common/logger';\n\nexport abstract class DAPublicationVerifierV1 {\n  protected readonly lensHubGateway: LensHubV1Gateway;\n\n  constructor(\n    public readonly daPublication: DAStructurePublication<DAEventTypeV1, PublicationV1TypedData>,\n    protected readonly ethereumNode: EthereumNode,\n    protected readonly log: LogFunctionType\n  ) {\n    this.lensHubGateway = new LensHubV1Gateway(ethereumNode);\n  }\n\n  public verifyPublicationIdMatches(): PromiseResult {\n    const generatedPublicationId = generatePublicationId(\n      this.daPublication.event.profileId,\n      this.daPublication.event.pubId,\n      this.daPublication.dataAvailabilityId\n    );\n\n    if (generatedPublicationId !== this.daPublication.publicationId) {\n      this.log('publicationId does not match the generated one');\n\n      return Promise.resolve(failure(MomokaValidatorError.GENERATED_PUBLICATION_ID_MISMATCH));\n    }\n\n    return Promise.resolve(success());\n  }\n\n  public async verifySigner(): PromiseResult<{\n    currentPublicationId: string;\n    ownerOfAddress: string;\n  }> {\n    const typedData = this.daPublication.chainProofs.thisPublication.typedData;\n\n    const whoSignedResult = await whoSignedTypedData(\n      typedData.domain,\n      typedData.types,\n      typedData.value,\n      this.daPublication.chainProofs.thisPublication.signature\n    );\n\n    if (whoSignedResult.isFailure()) {\n      return failure(whoSignedResult.failure);\n    }\n\n    const whoSigned = whoSignedResult.successResult;\n\n    this.log('who signed', whoSigned);\n\n    const chainProfileDetailsResult = await this.lensHubGateway.getOnChainProfileDetails(\n      this.daPublication.chainProofs.thisPublication.blockNumber,\n      typedData.value.profileId,\n      whoSigned\n    );\n    if (chainProfileDetailsResult.isFailure()) {\n      return failure(chainProfileDetailsResult.failure);\n    }\n\n    const details = chainProfileDetailsResult.successResult;\n\n    if (details.sigNonce !== typedData.value.nonce) {\n      this.log('nonce mismatch', { expected: details.sigNonce, actual: typedData.value.nonce });\n      return failure(MomokaValidatorError.PUBLICATION_NONCE_INVALID);\n    }\n\n    if (details.dispatcherAddress !== whoSigned && details.ownerOfAddress !== whoSigned) {\n      return failure(MomokaValidatorError.PUBLICATION_SIGNER_NOT_ALLOWED);\n    }\n\n    return success({\n      currentPublicationId: details.currentPublicationId,\n      ownerOfAddress: details.ownerOfAddress,\n    });\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/da-publication-verifier-v2.ts",
    "content": "import { failure, PromiseResult, success } from '../../data-availability-models/da-result';\nimport { DAEventTypeV2 } from '../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { PublicationV2TypedData } from '../../data-availability-models/publications/data-availability-publication-typed-data';\nimport { DAStructurePublication } from '../../data-availability-models/publications/data-availability-structure-publication';\nimport { whoSignedTypedData } from './publication.base';\nimport { MomokaValidatorError } from '../../data-availability-models/validator-errors';\nimport { EthereumNode } from '../../evm/ethereum';\nimport { LogFunctionType } from '../../common/logger';\nimport { LensHubV2Gateway } from '../../evm/gateway/LensHubV2Gateway';\n\nexport abstract class DAPublicationVerifierV2 {\n  protected readonly lensHubGateway: LensHubV2Gateway;\n\n  constructor(\n    public readonly daPublication: DAStructurePublication<DAEventTypeV2, PublicationV2TypedData>,\n    protected readonly ethereumNode: EthereumNode,\n    protected readonly log: LogFunctionType\n  ) {\n    this.lensHubGateway = new LensHubV2Gateway(ethereumNode);\n  }\n\n  abstract verifyPublicationIdMatches(): PromiseResult;\n\n  public async verifySigner(): PromiseResult<{\n    currentPublicationId: string;\n    ownerOfAddress: string;\n  }> {\n    const typedData = this.daPublication.chainProofs.thisPublication.typedData;\n\n    const whoSignedResult = await whoSignedTypedData(\n      typedData.domain,\n      typedData.types,\n      typedData.value,\n      this.daPublication.chainProofs.thisPublication.signature\n    );\n\n    if (whoSignedResult.isFailure()) {\n      return failure(whoSignedResult.failure);\n    }\n\n    const whoSigned = whoSignedResult.successResult;\n\n    this.log('who signed', whoSigned);\n\n    const chainProfileDetailsResult = await this.lensHubGateway.getOnChainProfileDetails(\n      this.daPublication.chainProofs.thisPublication.blockNumber,\n      typedData.value.profileId,\n      whoSigned\n    );\n\n    if (chainProfileDetailsResult.isFailure()) {\n      return failure(chainProfileDetailsResult.failure);\n    }\n\n    const details = chainProfileDetailsResult.successResult;\n\n    if (details.nonces !== typedData.value.nonce) {\n      this.log('nonce mismatch', { expected: details.nonces, actual: typedData.value.nonce });\n      return failure(MomokaValidatorError.PUBLICATION_NONCE_INVALID);\n    }\n\n    if (details.ownerOfAddress !== whoSigned && !details.isSignerApprovedExecutor) {\n      return failure(MomokaValidatorError.PUBLICATION_SIGNER_NOT_ALLOWED);\n    }\n\n    return success({\n      currentPublicationId: details.currentPublicationId,\n      ownerOfAddress: details.ownerOfAddress,\n    });\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/mirror/da-mirror-verifier-v1.ts",
    "content": "import { DAStructurePublication } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAMirrorCreatedEventEmittedResponseV1 } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { DAPublicationVerifierV1 } from '../da-publication-verifier-v1';\nimport { LogFunctionType } from '../../../common/logger';\nimport { failure, PromiseResult, success } from '../../../data-availability-models/da-result';\nimport { BigNumber } from 'ethers';\nimport { MomokaValidatorError } from '../../../data-availability-models/validator-errors';\nimport { EMPTY_BYTE, EthereumNode } from '../../../evm/ethereum';\nimport { CreateMirrorV1EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\n\nexport type DAMirrorPublicationV1 = DAStructurePublication<\n  DAMirrorCreatedEventEmittedResponseV1,\n  CreateMirrorV1EIP712TypedData\n>;\n\nexport const isDAMirrorPublicationV1 = (\n  daPublication: DAStructurePublication\n): daPublication is DAMirrorPublicationV1 => {\n  return (\n    daPublication.type === MomokaActionTypes.MIRROR_CREATED &&\n    !('mirrorParams' in daPublication.event)\n  );\n};\n\nexport class DAMirrorVerifierV1 extends DAPublicationVerifierV1 {\n  public readonly type = MomokaActionTypes.MIRROR_CREATED;\n\n  constructor(\n    public readonly daPublication: DAMirrorPublicationV1,\n    ethereumNode: EthereumNode,\n    log: LogFunctionType\n  ) {\n    super(daPublication, ethereumNode, log);\n  }\n\n  verifyEventWithTypedData(pubCountAtBlock: string): PromiseResult {\n    const event = this.daPublication.event;\n    const typedData = this.daPublication.chainProofs.thisPublication.typedData;\n\n    // compare all event emitted to typed data value\n    this.log('cross check event with typed data value');\n\n    // check the pub count makes sense from the block!\n    if (BigNumber.from(pubCountAtBlock).add(1).toHexString() !== event.pubId) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('pub count at block is correct');\n\n    // compare all others!\n    if (\n      typedData.value.profileId !== event.profileId ||\n      typedData.value.profileIdPointed !== event.profileIdPointed ||\n      typedData.value.pubIdPointed !== event.pubIdPointed ||\n      typedData.value.referenceModule !== event.referenceModule ||\n      event.referenceModuleReturnData !== EMPTY_BYTE ||\n      typedData.value.referenceModuleInitData !== EMPTY_BYTE\n    ) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('cross check event is complete');\n\n    return Promise.resolve(success());\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/mirror/da-mirror-verifier-v2.ts",
    "content": "import { DAStructurePublication } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAMirrorCreatedEventEmittedResponseV2 } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { CreateMirrorV2EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport { LogFunctionType } from '../../../common/logger';\nimport { failure, PromiseResult, success } from '../../../data-availability-models/da-result';\nimport { BigNumber } from 'ethers';\nimport { MomokaValidatorError } from '../../../data-availability-models/validator-errors';\nimport { DAPublicationVerifierV2 } from '../da-publication-verifier-v2';\nimport { generatePublicationId } from '../../utils';\nimport { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { EMPTY_BYTE, EthereumNode } from '../../../evm/ethereum';\nimport { arraysEqual } from '../../../utils/arrays-equal';\n\nexport type DAMirrorPublicationV2 = DAStructurePublication<\n  DAMirrorCreatedEventEmittedResponseV2,\n  CreateMirrorV2EIP712TypedData\n>;\n\nexport const isDAMirrorPublicationV2 = (\n  daPublication: DAStructurePublication\n): daPublication is DAMirrorPublicationV2 => {\n  return (\n    daPublication.type === MomokaActionTypes.MIRROR_CREATED && 'mirrorParams' in daPublication.event\n  );\n};\n\nexport class DAMirrorVerifierV2 extends DAPublicationVerifierV2 {\n  public readonly type = MomokaActionTypes.MIRROR_CREATED;\n\n  constructor(\n    public readonly daPublication: DAMirrorPublicationV2,\n    ethereumNode: EthereumNode,\n    log: LogFunctionType\n  ) {\n    super(daPublication, ethereumNode, log);\n  }\n\n  verifyPublicationIdMatches(): PromiseResult {\n    const generatedPublicationId = generatePublicationId(\n      this.daPublication.event.mirrorParams.profileId,\n      this.daPublication.event.pubId,\n      this.daPublication.dataAvailabilityId\n    );\n\n    if (generatedPublicationId !== this.daPublication.publicationId) {\n      this.log('publicationId does not match the generated one');\n\n      return Promise.resolve(failure(MomokaValidatorError.GENERATED_PUBLICATION_ID_MISMATCH));\n    }\n\n    return Promise.resolve(success());\n  }\n\n  verifyEventWithTypedData(pubCountAtBlock: string): PromiseResult {\n    const event = this.daPublication.event;\n    const typedData = this.daPublication.chainProofs.thisPublication.typedData;\n\n    // compare all event emitted to typed data value\n    this.log('cross check event with typed data value');\n\n    // check the pub count makes sense from the block!\n    if (BigNumber.from(pubCountAtBlock).add(1).toHexString() !== event.pubId) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('pub count at block is correct');\n\n    // compare all others!\n    if (\n      typedData.value.profileId !== event.mirrorParams.profileId ||\n      typedData.value.metadataURI !== event.mirrorParams.metadataURI ||\n      typedData.value.pointedProfileId !== event.mirrorParams.pointedProfileId ||\n      typedData.value.pointedPubId !== event.mirrorParams.pointedPubId ||\n      !arraysEqual(typedData.value.referrerProfileIds, event.mirrorParams.referrerProfileIds) ||\n      !arraysEqual(typedData.value.referrerPubIds, event.mirrorParams.referrerPubIds) ||\n      event.referenceModuleReturnData !== EMPTY_BYTE\n    ) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('cross check event is complete');\n\n    return Promise.resolve(success());\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/mirror/index.ts",
    "content": "import { LogFunctionType } from '../../../common/logger';\nimport { failure, PromiseResult } from '../../../data-availability-models/da-result';\nimport { DAPublicationPointerType } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { MomokaValidatorError } from '../../../data-availability-models/validator-errors';\nimport { EthereumNode } from '../../../evm/ethereum';\nimport { DaProofChecker } from '../../da-proof-checker';\nimport { DAMirrorVerifierV1 } from './da-mirror-verifier-v1';\nimport { DAMirrorVerifierV2 } from './da-mirror-verifier-v2';\n\n/**\n * Checks if the given DAMirrorPublication is valid by verifying the proof chain, cross-checking against the event, and\n * validating the signature.\n * @param daPublicationVerifier The verifier for the DACommentPublication.\n * @param verifyPointer If true, the pointer chain will be verified before checking the publication.\n * @param ethereumNode The EthereumNode to use for fetching data from the Ethereum blockchain.\n * @param log A function used for logging output.\n * @param checker The DAProofChecker to use for checking the proof.\n * @returns A PromiseResult indicating success or failure, along with an optional error message.\n */\nexport const checkDAMirror = async (\n  daPublicationVerifier: DAMirrorVerifierV1 | DAMirrorVerifierV2,\n  verifyPointer: boolean,\n  ethereumNode: EthereumNode,\n  log: LogFunctionType,\n  // TODO: Improve that to avoid cycling dependencies\n  checker: DaProofChecker\n): PromiseResult => {\n  log('check DA mirror');\n\n  const publication = daPublicationVerifier.daPublication;\n\n  if (!publication.chainProofs.pointer) {\n    return failure(MomokaValidatorError.PUBLICATION_NO_POINTER);\n  }\n\n  // only supports mirrors on DA at the moment\n  if (publication.chainProofs.pointer.type !== DAPublicationPointerType.ON_DA) {\n    return failure(MomokaValidatorError.PUBLICATION_NONE_DA);\n  }\n\n  if (verifyPointer) {\n    log('verify pointer first');\n\n    // check the pointer!\n    const pointerResult = await checker.checkDAProof(\n      publication.chainProofs.pointer.location,\n      ethereumNode,\n      {\n        verifyPointer: false,\n        byPassDb: false,\n        log,\n      }\n    );\n\n    if (pointerResult.isFailure()) {\n      return failure(MomokaValidatorError.POINTER_FAILED_VERIFICATION);\n    }\n  }\n\n  const signerResult = await daPublicationVerifier.verifySigner();\n\n  if (signerResult.isFailure()) {\n    return failure(signerResult.failure);\n  }\n\n  const eventResult = await daPublicationVerifier.verifyEventWithTypedData(\n    signerResult.successResult.currentPublicationId\n  );\n\n  log('finished checking DA mirror');\n\n  return eventResult;\n};\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/post/da-post-verifier-v1.ts",
    "content": "import { DAStructurePublication } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAPostCreatedEventEmittedResponseV1 } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { DAPublicationVerifierV1 } from '../da-publication-verifier-v1';\nimport { CreatePostV1EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport { LogFunctionType } from '../../../common/logger';\nimport { failure, PromiseResult, success } from '../../../data-availability-models/da-result';\nimport { BigNumber } from 'ethers';\nimport { MomokaValidatorError } from '../../../data-availability-models/validator-errors';\nimport {\n  blockHashExists,\n  EMPTY_BYTE,\n  EthereumNode,\n  executeSimulationTransaction,\n  parseSignature,\n} from '../../../evm/ethereum';\nimport { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { PostWithSig_DispatcherRequest } from '../../../evm/abi-types/LensHubV1';\n\nexport type DAPostPublicationV1 = DAStructurePublication<\n  DAPostCreatedEventEmittedResponseV1,\n  CreatePostV1EIP712TypedData\n>;\n\nexport const isDAPostPublicationV1 = (\n  daPublication: DAStructurePublication\n): daPublication is DAPostPublicationV1 => {\n  return (\n    daPublication.type === MomokaActionTypes.POST_CREATED && !('postParams' in daPublication.event)\n  );\n};\n\nexport class DAPostVerifierV1 extends DAPublicationVerifierV1 {\n  public readonly type = MomokaActionTypes.POST_CREATED;\n\n  constructor(\n    public readonly daPublication: DAPostPublicationV1,\n    ethereumNode: EthereumNode,\n    log: LogFunctionType\n  ) {\n    super(daPublication, ethereumNode, log);\n  }\n\n  async verifySimulation(): PromiseResult<string> {\n    const publication = this.daPublication;\n\n    const sigRequest: PostWithSig_DispatcherRequest = {\n      profileId: publication.chainProofs.thisPublication.typedData.value.profileId,\n      contentURI: publication.chainProofs.thisPublication.typedData.value.contentURI,\n      collectModule: publication.chainProofs.thisPublication.typedData.value.collectModule,\n      collectModuleInitData:\n        publication.chainProofs.thisPublication.typedData.value.collectModuleInitData,\n      referenceModule: publication.chainProofs.thisPublication.typedData.value.referenceModule,\n      referenceModuleInitData:\n        publication.chainProofs.thisPublication.typedData.value.referenceModuleInitData,\n      sig: parseSignature(\n        publication.chainProofs.thisPublication.signature,\n        publication.chainProofs.thisPublication.typedData.value.deadline\n      ),\n    };\n\n    this.log('signature simulation checking!', sigRequest);\n\n    const simulationData = await this.lensHubGateway.generatePostSimulationData(\n      publication.chainProofs.thisPublication.signedByDelegate,\n      sigRequest\n    );\n\n    if (simulationData.isFailure()) {\n      return failure(simulationData.failure);\n    }\n\n    // check the signature would of passed using eth_call\n    const [simulatedResult, expectedResult] = await Promise.all([\n      executeSimulationTransaction(\n        simulationData.successResult,\n        publication.chainProofs.thisPublication.blockNumber,\n        this.ethereumNode\n      ),\n      this.getExpectedResult(\n        publication.chainProofs.thisPublication.typedData.value.profileId,\n        publication.chainProofs.thisPublication.blockNumber\n      ),\n    ]);\n\n    if (simulatedResult.isFailure()) {\n      this.log('signature simulation checking failed');\n      return failure(simulatedResult.failure);\n    }\n\n    if (expectedResult.isFailure()) {\n      this.log('expectedResult failed to be fetched');\n      return failure(expectedResult.failure);\n    }\n\n    if (!expectedResult.successResult.eq(simulatedResult.successResult)) {\n      // recheck for `POTENTIAL_REORG`\n      const exists = await blockHashExists(\n        publication.chainProofs.thisPublication.blockHash,\n        this.ethereumNode\n      );\n      if (!exists) {\n        this.log('block hash now does not exist this could be a potential reorg');\n        return failure(MomokaValidatorError.POTENTIAL_REORG);\n      }\n\n      this.log('signature simulation checking failed');\n      return failure(MomokaValidatorError.SIMULATION_FAILED);\n    }\n\n    this.log('signature simulation passed!');\n\n    return success(simulatedResult.successResult);\n  }\n\n  verifyEventWithTypedData(simulatedPubResult: string): PromiseResult {\n    const event = this.daPublication.event;\n    const typedData = this.daPublication.chainProofs.thisPublication.typedData;\n\n    // compare all event emitted to typed data value\n    this.log('cross check event with typed data value');\n\n    // compare all others!\n    if (\n      !BigNumber.from(simulatedPubResult).eq(event.pubId) ||\n      typedData.value.profileId !== event.profileId ||\n      typedData.value.contentURI !== event.contentURI ||\n      typedData.value.collectModule !== event.collectModule ||\n      event.collectModuleReturnData !== EMPTY_BYTE ||\n      typedData.value.referenceModule !== event.referenceModule ||\n      event.referenceModuleReturnData !== EMPTY_BYTE ||\n      typedData.value.collectModuleInitData !== EMPTY_BYTE ||\n      typedData.value.referenceModuleInitData !== EMPTY_BYTE\n    ) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('cross check event is complete');\n\n    return Promise.resolve(success());\n  }\n\n  /**\n   * Expected result of simulation\n   * @param profileId The profile id\n   * @param blockNumber The block number\n   * @returns The expected result\n   */\n  private async getExpectedResult(\n    profileId: string,\n    blockNumber: number\n  ): PromiseResult<BigNumber> {\n    const publicationCount = await this.lensHubGateway.getLensPubCount(profileId, blockNumber);\n    if (publicationCount.isFailure()) {\n      return failure(publicationCount.failure);\n    }\n\n    return success(publicationCount.successResult.add(1));\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/post/da-post-verifier-v2.ts",
    "content": "import { DAStructurePublication } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAPostCreatedEventEmittedResponseV2 } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { CreatePostV2EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport { LogFunctionType } from '../../../common/logger';\nimport { failure, PromiseResult, success } from '../../../data-availability-models/da-result';\nimport { BigNumber } from 'ethers';\nimport { MomokaValidatorError } from '../../../data-availability-models/validator-errors';\nimport { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport {\n  blockHashExists,\n  EMPTY_BYTE,\n  EthereumNode,\n  executeSimulationTransaction,\n  parseSignature,\n} from '../../../evm/ethereum';\nimport { PostParamsRequest } from '../../../evm/abi-types/LensHubV2';\nimport { whoSignedTypedData } from '../publication.base';\nimport { DAPublicationVerifierV2 } from '../da-publication-verifier-v2';\nimport { generatePublicationId } from '../../utils';\nimport { arraysEqual } from '../../../utils/arrays-equal';\n\nexport type DAPostPublicationV2 = DAStructurePublication<\n  DAPostCreatedEventEmittedResponseV2,\n  CreatePostV2EIP712TypedData\n>;\n\nexport const isDAPostPublicationV2 = (\n  daPublication: DAStructurePublication\n): daPublication is DAPostPublicationV2 => {\n  return (\n    daPublication.type === MomokaActionTypes.POST_CREATED && 'postParams' in daPublication.event\n  );\n};\n\nexport class DAPostVerifierV2 extends DAPublicationVerifierV2 {\n  public readonly type = MomokaActionTypes.POST_CREATED;\n\n  constructor(\n    public readonly daPublication: DAPostPublicationV2,\n    ethereumNode: EthereumNode,\n    log: LogFunctionType\n  ) {\n    super(daPublication, ethereumNode, log);\n  }\n\n  verifyPublicationIdMatches(): PromiseResult {\n    const generatedPublicationId = generatePublicationId(\n      this.daPublication.event.postParams.profileId,\n      this.daPublication.event.pubId,\n      this.daPublication.dataAvailabilityId\n    );\n\n    if (generatedPublicationId !== this.daPublication.publicationId) {\n      this.log('publicationId does not match the generated one');\n\n      return Promise.resolve(failure(MomokaValidatorError.GENERATED_PUBLICATION_ID_MISMATCH));\n    }\n\n    return Promise.resolve(success());\n  }\n\n  async verifySimulation(): PromiseResult<string> {\n    const publication = this.daPublication;\n\n    const whoSignedResult = await whoSignedTypedData(\n      publication.chainProofs.thisPublication.typedData.domain,\n      publication.chainProofs.thisPublication.typedData.types,\n      publication.chainProofs.thisPublication.typedData.value,\n      publication.chainProofs.thisPublication.signature\n    );\n\n    if (whoSignedResult.isFailure()) {\n      return failure(whoSignedResult.failure);\n    }\n\n    const whoSigned = whoSignedResult.successResult;\n\n    this.log('who signed', whoSigned);\n\n    const sigRequest: PostParamsRequest = {\n      profileId: publication.chainProofs.thisPublication.typedData.value.profileId,\n      contentURI: publication.chainProofs.thisPublication.typedData.value.contentURI,\n      actionModules: publication.chainProofs.thisPublication.typedData.value.actionModules,\n      actionModulesInitDatas:\n        publication.chainProofs.thisPublication.typedData.value.actionModulesInitDatas,\n      referenceModule: publication.chainProofs.thisPublication.typedData.value.referenceModule,\n      referenceModuleInitData:\n        publication.chainProofs.thisPublication.typedData.value.referenceModuleInitData,\n    };\n\n    const signature = parseSignature(\n      publication.chainProofs.thisPublication.signature,\n      publication.chainProofs.thisPublication.typedData.value.deadline\n    );\n\n    this.log('signature simulation checking!', sigRequest);\n\n    const simulationData = await this.lensHubGateway.generatePostSimulationData(sigRequest, {\n      ...signature,\n      signer: whoSigned,\n    });\n\n    if (simulationData.isFailure()) {\n      return failure(simulationData.failure);\n    }\n\n    // check the signature would of passed using eth_call\n    const [expectedResult] = await Promise.all([\n      this.getExpectedResult(\n        publication.chainProofs.thisPublication.typedData.value.profileId,\n        publication.chainProofs.thisPublication.blockNumber\n      ),\n    ]);\n\n    // check the signature would of passed using eth_call\n    const [simulatedResult] = await Promise.all([\n      executeSimulationTransaction(\n        simulationData.successResult,\n        publication.chainProofs.thisPublication.blockNumber,\n        this.ethereumNode\n      ),\n    ]);\n\n    if (simulatedResult.isFailure()) {\n      this.log('signature simulation checking failed');\n      return failure(simulatedResult.failure);\n    }\n\n    if (expectedResult.isFailure()) {\n      this.log('expectedResult failed to be fetched');\n      return failure(expectedResult.failure);\n    }\n\n    if (!expectedResult.successResult.eq(simulatedResult.successResult)) {\n      // recheck for `POTENTIAL_REORG`\n      const exists = await blockHashExists(\n        publication.chainProofs.thisPublication.blockHash,\n        this.ethereumNode\n      );\n      if (!exists) {\n        this.log('block hash now does not exist this could be a potential reorg');\n        return failure(MomokaValidatorError.POTENTIAL_REORG);\n      }\n\n      this.log('signature simulation checking failed');\n      return failure(MomokaValidatorError.SIMULATION_FAILED);\n    }\n\n    this.log('signature simulation passed!');\n\n    return success(simulatedResult.successResult);\n  }\n\n  verifyEventWithTypedData(simulatedPubResult: string): PromiseResult {\n    const event = this.daPublication.event;\n    const typedData = this.daPublication.chainProofs.thisPublication.typedData;\n\n    // compare all event emitted to typed data value\n    this.log('cross check event with typed data value');\n\n    // compare all others!\n    if (\n      !BigNumber.from(simulatedPubResult).eq(event.pubId) ||\n      typedData.value.profileId !== event.postParams.profileId ||\n      typedData.value.contentURI !== event.postParams.contentURI ||\n      !arraysEqual(typedData.value.actionModules, event.postParams.actionModules) ||\n      !arraysEqual(\n        typedData.value.actionModulesInitDatas,\n        event.postParams.actionModulesInitDatas\n      ) ||\n      typedData.value.referenceModule !== event.postParams.referenceModule ||\n      typedData.value.referenceModuleInitData !== event.postParams.referenceModuleInitData ||\n      event.actionModulesInitReturnDatas.length !== 0 ||\n      event.referenceModuleInitReturnData !== EMPTY_BYTE\n    ) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('cross check event is complete');\n\n    return Promise.resolve(success());\n  }\n\n  /**\n   * Expected result of simulation\n   * @param profileId The profile id\n   * @param blockNumber The block number\n   * @returns The expected result\n   */\n  private async getExpectedResult(\n    profileId: string,\n    blockNumber: number\n  ): PromiseResult<BigNumber> {\n    const publicationCount = await this.lensHubGateway.getLensPubCount(profileId, blockNumber);\n    if (publicationCount.isFailure()) {\n      return failure(publicationCount.failure);\n    }\n\n    return success(publicationCount.successResult.add(1));\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/post/index.ts",
    "content": "import { LogFunctionType } from '../../../common/logger';\nimport { failure, PromiseResult } from '../../../data-availability-models/da-result';\nimport { MomokaValidatorError } from '../../../data-availability-models/validator-errors';\nimport { DAPostVerifierV1 } from './da-post-verifier-v1';\nimport { DAPostVerifierV2 } from './da-post-verifier-v2';\n\n/**\n * Checks if the given DAPostPublication is valid by verifying the proof chain, cross-checking against the event, and\n * validating the signature.\n * @param daPublicationVerifier The verifier for the DACommentPublication.\n * @param log A function used for logging output.\n * @returns A PromiseResult indicating success or failure, along with an optional error message.\n */\nexport const checkDAPost = async (\n  daPublicationVerifier: DAPostVerifierV1 | DAPostVerifierV2,\n  log: LogFunctionType\n): PromiseResult => {\n  log('check DA post');\n\n  const publication = daPublicationVerifier.daPublication;\n\n  if (publication.chainProofs.pointer) {\n    return failure(MomokaValidatorError.INVALID_POINTER_SET_NOT_NEEDED);\n  }\n\n  const simulatedResult = await daPublicationVerifier.verifySimulation();\n\n  if (simulatedResult.isFailure()) {\n    return failure(simulatedResult.failure);\n  }\n\n  // cross-check event and typed data values\n  const eventResult = daPublicationVerifier.verifyEventWithTypedData(simulatedResult.successResult);\n\n  log('finished checking DA post');\n\n  return eventResult;\n};\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/publication.base.ts",
    "content": "import { SignatureLike } from '@ethersproject/bytes';\nimport { utils } from 'ethers';\nimport { failure, PromiseResult, success } from '../../data-availability-models/da-result';\nimport {\n  TypedDataDomain,\n  TypedDataField,\n} from '../../data-availability-models/data-availability-typed-data';\nimport { MomokaValidatorError } from '../../data-availability-models/validator-errors';\n\n/**\n * Verifies the provided signature corresponds to the given typed data and returns the address of the signer.\n * @param domain The typed data domain.\n * @param types The typed data types.\n * @param value The typed data value.\n * @param signature The signature to verify.\n * @returns A `success` result with the signer's address if the signature is valid, or a `failure` result with a `MomokaValidatorError` if there's an error during the verification process.\n            turned into a promise as its minimum CPU intensive\n */\nexport const whoSignedTypedData = (\n  domain: TypedDataDomain,\n  types: Record<string, Array<TypedDataField>>,\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  value: Record<string, any>,\n  signature: SignatureLike\n): PromiseResult<string> => {\n  try {\n    const address = utils.verifyTypedData(domain, types, value, signature);\n    return Promise.resolve(success(address));\n  } catch {\n    return Promise.resolve(failure(MomokaValidatorError.INVALID_FORMATTED_TYPED_DATA));\n  }\n};\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/quote/da-quote-verifier-v2.ts",
    "content": "import { DAStructurePublication } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { DAQuoteCreatedEventEmittedResponseV2 } from '../../../data-availability-models/publications/data-availability-structure-publications-events';\nimport { CreateQuoteV2EIP712TypedData } from '../../../data-availability-models/publications/data-availability-publication-typed-data';\nimport { LogFunctionType } from '../../../common/logger';\nimport { failure, PromiseResult, success } from '../../../data-availability-models/da-result';\nimport { BigNumber } from 'ethers';\nimport { MomokaValidatorError } from '../../../data-availability-models/validator-errors';\nimport { DAPublicationVerifierV2 } from '../da-publication-verifier-v2';\nimport { generatePublicationId } from '../../utils';\nimport { MomokaActionTypes } from '../../../data-availability-models/data-availability-action-types';\nimport { EMPTY_BYTE, EthereumNode } from '../../../evm/ethereum';\nimport { arraysEqual } from '../../../utils/arrays-equal';\n\nexport type DAQuotePublicationV2 = DAStructurePublication<\n  DAQuoteCreatedEventEmittedResponseV2,\n  CreateQuoteV2EIP712TypedData\n>;\n\nexport const isDAQuotePublicationV2 = (\n  daPublication: DAStructurePublication\n): daPublication is DAQuotePublicationV2 => {\n  return (\n    daPublication.type === MomokaActionTypes.QUOTE_CREATED && 'quoteParams' in daPublication.event\n  );\n};\n\nexport class DAQuoteVerifierV2 extends DAPublicationVerifierV2 {\n  public readonly type = MomokaActionTypes.QUOTE_CREATED;\n\n  constructor(\n    public readonly daPublication: DAQuotePublicationV2,\n    ethereumNode: EthereumNode,\n    log: LogFunctionType\n  ) {\n    super(daPublication, ethereumNode, log);\n  }\n\n  verifyPublicationIdMatches(): PromiseResult {\n    const generatedPublicationId = generatePublicationId(\n      this.daPublication.event.quoteParams.profileId,\n      this.daPublication.event.pubId,\n      this.daPublication.dataAvailabilityId\n    );\n\n    if (generatedPublicationId !== this.daPublication.publicationId) {\n      this.log('publicationId does not match the generated one');\n\n      return Promise.resolve(failure(MomokaValidatorError.GENERATED_PUBLICATION_ID_MISMATCH));\n    }\n\n    return Promise.resolve(success());\n  }\n\n  verifyEventWithTypedData(pubCountAtBlock: string): PromiseResult {\n    const event = this.daPublication.event;\n    const typedData = this.daPublication.chainProofs.thisPublication.typedData;\n\n    // compare all event emitted to typed data value\n    this.log('cross check event with typed data value');\n\n    // check the pub count makes sense from the block!\n    if (BigNumber.from(pubCountAtBlock).add(1).toHexString() !== event.pubId) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('pub count at block is correct');\n\n    // compare all others!\n    if (\n      typedData.value.profileId !== event.quoteParams.profileId ||\n      typedData.value.contentURI !== event.quoteParams.contentURI ||\n      typedData.value.pointedProfileId !== event.quoteParams.pointedProfileId ||\n      typedData.value.pointedPubId !== event.quoteParams.pointedPubId ||\n      !arraysEqual(typedData.value.actionModules, event.quoteParams.actionModules) ||\n      !arraysEqual(\n        typedData.value.actionModulesInitDatas,\n        event.quoteParams.actionModulesInitDatas\n      ) ||\n      typedData.value.referenceModule !== event.quoteParams.referenceModule ||\n      typedData.value.referenceModuleInitData !== event.quoteParams.referenceModuleInitData ||\n      !arraysEqual(typedData.value.referrerProfileIds, event.quoteParams.referrerProfileIds) ||\n      !arraysEqual(typedData.value.referrerPubIds, event.quoteParams.referrerPubIds) ||\n      event.actionModulesInitReturnDatas.length !== 0 ||\n      event.referenceModuleReturnData !== EMPTY_BYTE ||\n      event.referenceModuleInitReturnData !== EMPTY_BYTE\n    ) {\n      return Promise.resolve(failure(MomokaValidatorError.EVENT_MISMATCH));\n    }\n\n    this.log('cross check event is complete');\n\n    return Promise.resolve(success());\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/proofs/publications/quote/index.ts",
    "content": "import { LogFunctionType } from '../../../common/logger';\nimport { failure, PromiseResult } from '../../../data-availability-models/da-result';\nimport { DAPublicationPointerType } from '../../../data-availability-models/publications/data-availability-structure-publication';\nimport { MomokaValidatorError } from '../../../data-availability-models/validator-errors';\nimport { EthereumNode } from '../../../evm/ethereum';\nimport { DaProofChecker } from '../../da-proof-checker';\nimport { DAQuoteVerifierV2 } from './da-quote-verifier-v2';\n\n/**\n * Checks if the given DAQuotePublication is valid by verifying the proof chain, cross-checking against the event, and\n * validating the signature.\n * @param daPublicationVerifier The verifier for the DAQuotePublication.\n * @param verifyPointer If true, the pointer chain will be verified before checking the publication.\n * @param ethereumNode The EthereumNode to use for fetching data from the Ethereum blockchain.\n * @param log A function used for logging output.\n * @param checker The DAProofChecker to use for checking the proof.\n * @returns A PromiseResult indicating success or failure, along with an optional error message.\n */\nexport const checkDAQuote = async (\n  daPublicationVerifier: DAQuoteVerifierV2,\n  verifyPointer: boolean,\n  ethereumNode: EthereumNode,\n  log: LogFunctionType,\n  checker: DaProofChecker\n): PromiseResult => {\n  log('check DA quote');\n\n  const publication = daPublicationVerifier.daPublication;\n\n  if (!publication.chainProofs.pointer) {\n    return failure(MomokaValidatorError.PUBLICATION_NO_POINTER);\n  }\n\n  if (publication.chainProofs.pointer.type !== DAPublicationPointerType.ON_DA) {\n    return failure(MomokaValidatorError.PUBLICATION_NONE_DA);\n  }\n\n  if (verifyPointer) {\n    log('verify pointer first');\n\n    // check the pointer!\n    const pointerResult = await checker.checkDAProof(\n      publication.chainProofs.pointer.location,\n      ethereumNode,\n      {\n        byPassDb: false,\n        verifyPointer: false,\n        log,\n      }\n    );\n    if (pointerResult.isFailure()) {\n      return failure(MomokaValidatorError.POINTER_FAILED_VERIFICATION);\n    }\n  }\n\n  const signerResult = await daPublicationVerifier.verifySigner();\n\n  if (signerResult.isFailure()) {\n    return failure(signerResult.failure);\n  }\n\n  const eventResult = await daPublicationVerifier.verifyEventWithTypedData(\n    signerResult.successResult.currentPublicationId\n  );\n\n  log('finished checking DA quote');\n\n  return eventResult;\n};\n"
  },
  {
    "path": "momoka-node/src/proofs/utils.ts",
    "content": "import type CryptoInterface from 'arweave/node/lib/crypto/crypto-interface';\nimport { BlockInfo } from '../evm/ethereum';\nimport { unixTimestampToMilliseconds } from '../common/helpers';\nimport { DAStructurePublication } from '../data-availability-models/publications/data-availability-structure-publication';\nimport { BundlrUploadResponse } from '../data-availability-models/data-availability-timestamp-proofs';\nimport { BigNumberish } from 'ethers';\n\n/**\n * Finds the closest block based on timestamp in milliseconds.\n * @param blocks List of blocks to search through\n * @param targetTimestamp Timestamp in milliseconds to match against block timestamp\n * @returns The block with the closest matching timestamp\n */\nexport const getClosestBlock = (blocks: BlockInfo[], targetTimestamp: number): BlockInfo => {\n  const targetTimestampMs = unixTimestampToMilliseconds(targetTimestamp);\n\n  return blocks.reduce((prev, curr) => {\n    const prevTimestamp = unixTimestampToMilliseconds(prev.timestamp);\n    const currTimestamp = unixTimestampToMilliseconds(curr.timestamp);\n\n    if (currTimestamp > targetTimestampMs) {\n      return prev;\n    }\n\n    const prevDifference = Math.abs(prevTimestamp - targetTimestampMs);\n    const currDifference = Math.abs(currTimestamp - targetTimestampMs);\n\n    return currDifference < prevDifference ? curr : prev;\n  });\n};\n\n/**\n * Generates the unique ID for a DAStructurePublication.\n * @param profileId The profile ID of the publication.\n * @param publicationId The publication ID of the publication.\n * @param dataAvailabilityId The data availability ID of the publication.\n */\nexport const generatePublicationId = (\n  profileId: BigNumberish,\n  publicationId: BigNumberish,\n  dataAvailabilityId: string\n): string => {\n  return `${profileId}-${publicationId}-DA-${dataAvailabilityId.split('-')[0]}`;\n};\n\n/**\n * Checks if the typed data deadline timestamp in the given DAStructurePublication matches\n * the block timestamp of the containing block.\n * @param daPublication The DAStructurePublication to check.\n * @returns True if the typed data deadline timestamp matches the block timestamp, false otherwise.\n */\nexport const isValidTypedDataDeadlineTimestamp = (\n  daPublication: DAStructurePublication\n): boolean => {\n  return (\n    daPublication.chainProofs.thisPublication.typedData.value.deadline ===\n    daPublication.chainProofs.thisPublication.blockTimestamp\n  );\n};\n\n/**\n * Checks if the event timestamp in the given DA publication matches the publication timestamp of the block it was included in.\n * @param daPublication The DA publication to check.\n * @returns A boolean indicating whether or not the event timestamp matches the publication timestamp.\n */\nexport const isValidEventTimestamp = (daPublication: DAStructurePublication): boolean => {\n  return daPublication.event.timestamp === daPublication.chainProofs.thisPublication.blockTimestamp;\n};\n\ntype Providers = {\n  stringToBuffer: (str: string) => Uint8Array;\n  b64UrlToBuffer: (str: string) => Uint8Array;\n  deepHash: (str: Uint8Array[]) => Promise<Uint8Array>;\n  crypto: CryptoInterface;\n};\n\n/**\n * Verifies the signature of a Bundlr upload response.\n * Copied from https://github.com/Bundlr-Network/js-sdk/blob/main/src/common/utils.ts to make the code isomorphic\n * and avoid bringing node native modules to client code.\n * @param response The Bundlr upload response to verify.\n * @param providers The providers to use for the verification (should be either the one for node or client).\n */\nexport const verifyReceipt = async (\n  { deadlineHeight, id, public: pubKey, signature, timestamp, version }: BundlrUploadResponse,\n  { crypto, b64UrlToBuffer, stringToBuffer, deepHash }: Providers\n): Promise<boolean> => {\n  const dh = await deepHash([\n    stringToBuffer('Bundlr'),\n    stringToBuffer(version),\n    stringToBuffer(id),\n    stringToBuffer(deadlineHeight.toString()),\n    stringToBuffer(timestamp.toString()),\n  ]);\n\n  return await crypto.verify(pubKey, dh, b64UrlToBuffer(signature));\n};\n"
  },
  {
    "path": "momoka-node/src/queue/base.queue.ts",
    "content": "import { sleep } from '../common/helpers';\n\n/**\n * A queue is a data structure that follows the FIFO (First In First Out) principle.\n */\nexport class Queue<T> {\n  private items: T[];\n\n  constructor() {\n    this.items = [];\n  }\n\n  public enqueue(item: T): void {\n    this.items.push(item);\n  }\n\n  /**\n   *  Enqueues an item with a delay to not spam the event loop\n   * @param item The item\n   * @param delay The delay in milliseconds\n   */\n  public async enqueueWithDelay(item: T, delay: number): Promise<void> {\n    await sleep(delay);\n    this.enqueue(item);\n  }\n\n  public dequeue(): T | undefined {\n    if (this.isEmpty()) {\n      return undefined;\n    }\n    return this.items.shift();\n  }\n\n  public isEmpty(): boolean {\n    return this.items.length === 0;\n  }\n}\n"
  },
  {
    "path": "momoka-node/src/queue/known.queue.ts",
    "content": "import { Queue } from './base.queue';\nimport { ProcessFailedProofQueueRequest } from './process-failed-da-proof.queue';\nimport { ProcessRetryCheckDAProofsQueueRequest } from './process-retry-check-da-proofs.queue';\n\n/**\n * The failed proofs queue\n */\nexport const failedDAProofQueue = new Queue<ProcessFailedProofQueueRequest>();\n/**\n * The retry check proofs queue\n */\nexport const retryCheckDAProofsQueue = new Queue<ProcessRetryCheckDAProofsQueueRequest>();\n"
  },
  {
    "path": "momoka-node/src/queue/process-failed-da-proof.queue.ts",
    "content": "import { existsSync, promises as fs } from 'fs';\nimport { runForever } from '../common/helpers';\nimport { MomokaValidatorError } from '../data-availability-models/validator-errors';\nimport { failedProofsPath, pathResolver } from '../input-output/paths';\nimport { Queue } from './base.queue';\nimport { failedDAProofQueue } from './known.queue';\n\nexport interface ProcessFailedProofQueueRequest {\n  txId: string;\n  reason: MomokaValidatorError;\n  submitter: string;\n}\n\nconst writeFailedProof = async (failed: ProcessFailedProofQueueRequest): Promise<void> => {\n  const path = await pathResolver();\n  const failedPath = await failedProofsPath();\n  const errorLocation = path.join(failedPath, failed.reason);\n  if (!existsSync(errorLocation)) {\n    await fs.mkdir(errorLocation);\n  }\n\n  await fs.writeFile(path.join(errorLocation, failed.txId + '.json'), JSON.stringify(failed));\n};\n\n/**\n * Processes the failed proofs queue to save them on disk\n * @param failedQueue - The failed proofs queue\n */\nexport const processFailedDAProofQueue = async (\n  failedQueue: Queue<ProcessFailedProofQueueRequest>\n): Promise<void> => {\n  await runForever(async () => {\n    if (!failedQueue.isEmpty()) {\n      const failed = failedQueue.dequeue();\n      if (failed) {\n        try {\n          await writeFailedProof(failed);\n        } catch (e) {\n          console.error(\n            'Error writing the disk for failed publication.. make sure you have enough disk space',\n            {\n              error: e,\n            }\n          );\n\n          // add back in the queue in 30 seconds for retry\n          failedDAProofQueue.enqueueWithDelay(failed, 30000);\n        }\n      }\n    }\n  }, 200);\n};\n"
  },
  {
    "path": "momoka-node/src/queue/process-retry-check-da-proofs.queue.ts",
    "content": "import { runForever } from '../common/helpers';\nimport { MomokaValidatorError } from '../data-availability-models/validator-errors';\nimport { EthereumNode } from '../evm/ethereum';\nimport { checkDAProofsBatch } from '../proofs/check-da-proofs-batch';\nimport { StreamCallback } from '../watchers/models/stream.type';\nimport { Queue } from './base.queue';\nimport { retryCheckDAProofsQueue } from './known.queue';\n\nexport interface ProcessRetryCheckDAProofsQueueRequest {\n  txIds: string[];\n  ethereumNode: EthereumNode;\n  stream: StreamCallback | undefined;\n}\n\n/**\n * Validation errors whcih should be retried due to network issues out of\n * control of the proof verifier.\n * @param validatorError The validation error to check.\n */\nexport const shouldRetry = (validatorError: MomokaValidatorError): boolean => {\n  return (\n    validatorError === MomokaValidatorError.UNKNOWN ||\n    validatorError === MomokaValidatorError.CAN_NOT_CONNECT_TO_BUNDLR ||\n    validatorError === MomokaValidatorError.BLOCK_CANT_BE_READ_FROM_NODE ||\n    validatorError === MomokaValidatorError.DATA_CANT_BE_READ_FROM_NODE ||\n    validatorError === MomokaValidatorError.SIMULATION_NODE_COULD_NOT_RUN\n  );\n};\n\n/**\n * Processes the retry check proofs queue to check the proofs again (due to fails based on stuff which isnt valid)\n * @param retryQueue - The retry check proofs queue\n * @param usLocalNode - A boolean to indicate whether to use the local node.\n */\nexport const processRetryCheckDAProofsQueue = async (\n  retryQueue: Queue<ProcessRetryCheckDAProofsQueueRequest>,\n  concurrency: number,\n  usLocalNode = false\n): Promise<void> => {\n  await runForever(async () => {\n    if (!retryQueue.isEmpty()) {\n      const proofs = retryQueue.dequeue();\n      if (proofs && proofs.txIds.length > 0) {\n        try {\n          await checkDAProofsBatch(\n            proofs.txIds,\n            proofs.ethereumNode,\n            true,\n            concurrency,\n            usLocalNode,\n            proofs.stream\n          );\n        } catch (e) {\n          // add back in the queue in 30 seconds for retry\n          retryCheckDAProofsQueue.enqueueWithDelay(proofs, 30000);\n        }\n      }\n    }\n  }, 200);\n};\n"
  },
  {
    "path": "momoka-node/src/queue/startup.queue.ts",
    "content": "import { failedDAProofQueue, retryCheckDAProofsQueue } from './known.queue';\nimport { processFailedDAProofQueue } from './process-failed-da-proof.queue';\nimport { processRetryCheckDAProofsQueue } from './process-retry-check-da-proofs.queue';\n\n/**\n * Starts the queues up\n */\nexport const startupQueues = (concurrency: number): void => {\n  processFailedDAProofQueue(failedDAProofQueue);\n  processRetryCheckDAProofsQueue(retryCheckDAProofsQueue, concurrency);\n};\n"
  },
  {
    "path": "momoka-node/src/runnable/da-verifier-node.runnable.ts",
    "content": "import { getParam, turnedOffExperimentalWarning } from '../common/helpers';\nimport { startDAVerifierNode } from '../watchers/verifier.watcher';\nimport { ethereumNode } from './ethereum-node-instance';\n\nturnedOffExperimentalWarning();\n\nconst concurrencyRaw = getParam('CONCURRENCY');\nconst concurrency = concurrencyRaw ? Number(concurrencyRaw) : 100;\n\nstartDAVerifierNode(ethereumNode, concurrency).catch((error) => {\n  console.error('DA verifier node failed to startup', error);\n  process.exitCode = 1;\n});\n"
  },
  {
    "path": "momoka-node/src/runnable/ethereum-node-instance.ts",
    "content": "import { Deployment, Environment } from '../common/environment';\nimport { getParam, getParamOrExit } from '../common/helpers';\nimport { EthereumNode } from '../evm/ethereum';\n\nexport const ethereumNode: EthereumNode = {\n  environment: getParamOrExit('ETHEREUM_NETWORK') as Environment,\n  nodeUrl: getParamOrExit('NODE_URL'),\n  deployment: (getParam('DEPLOYMENT') as Deployment) || Deployment.PRODUCTION,\n};\n"
  },
  {
    "path": "momoka-node/src/runnable/failed-submissons.runnable.ts",
    "content": "import { verifierFailedSubmissionsWatcher } from '../watchers/failed-submissons.watcher';\n\n/**\n * Watches for failed submissions in the database and logs a summary of the errors.\n */\nverifierFailedSubmissionsWatcher().catch((error) => {\n  console.error('DA verifier failed watcher failed to startup', error);\n  process.exitCode = 1;\n});\n"
  },
  {
    "path": "momoka-node/src/submitters.ts",
    "content": "import { Deployment, Environment } from './common/environment';\n\n/**\n * Returns the list of submitters based on the given environment and deployment\n * @param environment - The environment to get the submitters for\n * @param deployment - The deployment to get the submitters for. Defaults to Deployment.PRODUCTION\n * @returns An array of submitter addresses in lowercase\n */\nexport const getSubmitters = (\n  environment: Environment,\n  deployment: Deployment = Deployment.PRODUCTION\n): string[] => {\n  // this will come from a smart contract later on!\n\n  if (deployment === Deployment.PRODUCTION) {\n    switch (environment) {\n      case Environment.POLYGON:\n        return ['0xBe29464B9784a0d8956f29630d8bc4D7B5737435'.toLowerCase()];\n      case Environment.MUMBAI:\n        return ['0xF1143C45953066718dE115578cf31c237B062a15'.toLowerCase()];\n      case Environment.AMOY:\n        return ['0x085be9a079aB75608fB794f2D288A375856e3f60'.toLowerCase()];\n      default:\n        throw new Error('Invalid environment');\n    }\n  }\n\n  if (deployment === Deployment.STAGING) {\n    switch (environment) {\n      case Environment.POLYGON:\n        throw new Error('Not Supported');\n      case Environment.MUMBAI:\n        return ['0x55307bfae6DF8988F59FE20272bC68792b130415'.toLowerCase()];\n      case Environment.AMOY:\n        return ['0xC1b3BF1D611f1148F1799E90f7342860499Ba9D9'.toLowerCase()];\n      default:\n        throw new Error('Invalid environment');\n    }\n  }\n\n  if (deployment === Deployment.LOCAL) {\n    switch (environment) {\n      case Environment.POLYGON:\n        throw new Error('Not Supported');\n      case Environment.MUMBAI:\n        return ['0x8Fc176aA6FC843D3422f0C1832f1b9E17be00C1c'.toLowerCase()];\n      case Environment.AMOY:\n        return ['0xcD7739d0b2ceFAb809FEF4e839a55b2627B60205'.toLowerCase()];\n      default:\n        throw new Error('Invalid environment');\n    }\n  }\n\n  throw new Error('Invalid deployment');\n};\n\n/**\n * Checks if an Ethereum address is a valid submitter for the given environment and deployment.\n * @param environment The environment (Polygon, Mumbai, or Sandbox).\n * @param address The Ethereum address to check.\n * @param deployment The deployment (Production, Staging, or Local). Defaults to Production.\n * @returns True if the address is a valid submitter, false otherwise.\n */\nexport const isValidSubmitter = (\n  environment: Environment,\n  address: string,\n  deployment?: Deployment\n): boolean => {\n  return getSubmitters(environment, deployment).includes(address.toLowerCase());\n};\n"
  },
  {
    "path": "momoka-node/src/utils/arrays-equal.ts",
    "content": "export const arraysEqual = <T>(array1: T[], array2: T[]): boolean => {\n  if (array1.length !== array2.length) {\n    return false;\n  }\n\n  for (let i = 0; i < array1.length; i++) {\n    if (array1[i] !== array2[i]) {\n      return false;\n    }\n  }\n\n  return true;\n};\n"
  },
  {
    "path": "momoka-node/src/utils/invariant.ts",
    "content": "export class InvariantError extends Error {\n  constructor(message: string) {\n    super(`InvariantError: ${message}`);\n  }\n}\n\ntype Invariant = (condition: unknown, message: string) => asserts condition;\n\n/**\n * Asserts that the given condition is truthy\n *\n * @param condition - Either truthy or falsy value\n * @param message - An error message\n */\nexport const invariant: Invariant = (condition: unknown, message: string): asserts condition => {\n  if (!condition) {\n    throw new InvariantError(message);\n  }\n};\n"
  },
  {
    "path": "momoka-node/src/utils/number-to-hex.ts",
    "content": "/**\n * Does this over ethers call as alchemy and some other providers dont like a padding hex number\n * - wont accept 0x01f1a494\n * - will accept 0x1f1a494\n * @param number\n * @returns\n */\nexport const numberToHex = (number: number): string => {\n  return '0x' + number.toString(16);\n};\n"
  },
  {
    "path": "momoka-node/src/watchers/failed-submissons.watcher.ts",
    "content": "import { existsSync, promises as fs } from 'fs';\nimport path from 'path';\nimport { runForever } from '../common/helpers';\nimport { consoleLogWithLensNodeFootprint } from '../common/logger';\nimport { MomokaValidatorError } from '../data-availability-models/validator-errors';\nimport { failedProofsPath } from '../input-output/paths';\nimport { shouldRetry } from '../queue/process-retry-check-da-proofs.queue';\n\n/**\n * Watches for failed submissions written to disk\n */\nexport const verifierFailedSubmissionsWatcher = async (): Promise<void> => {\n  consoleLogWithLensNodeFootprint('started up failed submission watcher...');\n\n  let firstRun = true;\n  await runForever(async () => {\n    if (firstRun) {\n      firstRun = false;\n    } else {\n      try {\n        const failedPath = await failedProofsPath();\n        const failedResults = [];\n        // Count the number of failed submissions for each error reason\n        for (const item in MomokaValidatorError) {\n          if (isNaN(Number(item))) {\n            if (!shouldRetry(item as MomokaValidatorError)) {\n              const errorPath = path.join(failedPath, item);\n              const errorCount = existsSync(errorPath)\n                ? (await fs.readdir(path.join(failedPath, item))).length\n                : 0;\n\n              failedResults.push([item, errorCount]);\n            }\n          }\n        }\n        console.table(failedResults);\n      } catch (error) {\n        consoleLogWithLensNodeFootprint(\n          'verifier failed watcher failed try again in 5 seconds',\n          error\n        );\n      }\n    }\n  }, 60000);\n};\n"
  },
  {
    "path": "momoka-node/src/watchers/models/start-da-verifier-node-options.ts",
    "content": "import { StreamCallback } from './stream.type';\n\n/**\n * Options for starting the verifier node\n */\nexport interface StartDAVerifierNodeOptions {\n  /**\n   * The callback function to be called when a new result is available\n   */\n  stream?: StreamCallback | undefined;\n\n  /**\n   * if true, the verifier node will resync back from zero\n   * and will not sync from the genesis block\n   */\n  resync?: boolean | undefined;\n}\n"
  },
  {
    "path": "momoka-node/src/watchers/models/stream.type.ts",
    "content": "import { TxValidatedResult } from '../../input-output/tx-validated-results';\n\nexport type StreamResult = TxValidatedResult;\nexport type StreamCallback = (result: StreamResult) => void;\n"
  },
  {
    "path": "momoka-node/src/watchers/trusting-indexing.watcher.ts",
    "content": "import { Deployment, Environment } from '../common/environment';\nimport { runForever, sleep } from '../common/helpers';\nimport { consoleLog } from '../common/logger';\nimport { getBundlrBulkTxsAPI } from '../input-output/bundlr/get-bundlr-bulk-txs.api';\nimport {\n  DataAvailabilityTransactionsOrderTypes,\n  getDataAvailabilityTransactionsAPI,\n  getDataAvailabilityTransactionsAPIResponse,\n} from '../input-output/bundlr/get-data-availability-transactions.api';\nimport { TIMEOUT_ERROR } from '../input-output/common';\nimport { buildDAPublicationsBatchResult } from '../proofs/check-da-proofs-batch';\nimport { StreamCallback } from './models/stream.type';\n\n/**\n * The DA trusting indexer request.\n */\nexport interface StartDATrustingIndexingRequest {\n  stream: StreamCallback;\n  environment: Environment;\n  /**\n   * The deployment to use, only use this if you know what you are doing.\n   */\n  deployment?: Deployment;\n}\n\n/**\n * Starts the DA trusting indexing to watch for new data availability coming in and index them.\n * @param request The trusting index request\n */\nexport const startDATrustingIndexing = async (\n  request: StartDATrustingIndexingRequest\n): Promise<never> => {\n  consoleLog('LENS DA TRUSTING INDEXING - DA verification indexing starting...');\n\n  let endCursor: string | null = null;\n\n  return await runForever(async () => {\n    try {\n      // Get new data availability transactions from the server.\n      const arweaveTransactions: getDataAvailabilityTransactionsAPIResponse =\n        await getDataAvailabilityTransactionsAPI(\n          request.environment,\n          request.deployment,\n          endCursor,\n          DataAvailabilityTransactionsOrderTypes.ASC\n        );\n\n      if (arweaveTransactions.edges.length === 0) {\n        consoleLog('LENS DA TRUSTING INDEXING - No new DA items found..');\n        // Sleep for 100ms before checking again.\n        await sleep(100);\n      } else {\n        consoleLog(\n          'LENS DA TRUSTING INDEXING - Found new submissions...',\n          arweaveTransactions.edges.length\n        );\n\n        const bulkDAProofs = await getBundlrBulkTxsAPI(\n          arweaveTransactions.edges.map((edge) => edge.node.id)\n        );\n        if (bulkDAProofs === TIMEOUT_ERROR) {\n          throw new Error('getBundlrBulkTxsAPI for proofs timed out');\n        }\n\n        // Build the data availability publication result for each submission.\n        const daPublications = await buildDAPublicationsBatchResult(bulkDAProofs.success);\n\n        // Stream the results to the callback.\n        daPublications.map((publication) => {\n          request.stream({\n            proofTxId: publication.id,\n            success: true,\n            dataAvailabilityResult: publication.daPublication,\n          });\n        });\n\n        endCursor = arweaveTransactions.pageInfo.endCursor;\n      }\n    } catch (error) {\n      consoleLog('LENS DA TRUSTING INDEXING - Error while checking for new submissions', error);\n      await sleep(100);\n    }\n  });\n};\n"
  },
  {
    "path": "momoka-node/src/watchers/verifier.watcher.ts",
    "content": "import { Deployment, Environment } from '../common/environment';\nimport { runForever, sleep } from '../common/helpers';\nimport { consoleLogWithLensNodeFootprint } from '../common/logger';\nimport { LOCAL_NODE_URL, setupAnvilLocalNode } from '../evm/anvil';\nimport { EthereumNode } from '../evm/ethereum';\nimport {\n  DataAvailabilityTransactionsOrderTypes,\n  getDataAvailabilityTransactionsAPI,\n} from '../input-output/bundlr/get-data-availability-transactions.api';\nimport {\n  getLastEndCursorDb,\n  getTotalCheckedCountDb,\n  saveEndCursorDb,\n  saveTotalCheckedCountDb,\n  startDb,\n} from '../input-output/db';\nimport { checkDAProofsBatch } from '../proofs/check-da-proofs-batch';\nimport { retryCheckDAProofsQueue } from '../queue/known.queue';\nimport { shouldRetry } from '../queue/process-retry-check-da-proofs.queue';\nimport { startupQueues } from '../queue/startup.queue';\n// import { verifierFailedSubmissionsWatcher } from './failed-submissons.watcher';\nimport { StartDAVerifierNodeOptions } from './models/start-da-verifier-node-options';\nimport { StreamCallback } from './models/stream.type';\n\n/**\n *  Starts up the verifier node\n * @param ethereumNode The Ethereum node to use for verification.\n * @param concurrency The concurrency to use < this is how many TCP it will run at\n * @param usLocalNode A boolean to indicate whether to use the local node.\n */\nconst startup = async (\n  ethereumNode: EthereumNode,\n  concurrency: number,\n  usLocalNode: boolean\n): Promise<void> => {\n  if (usLocalNode) {\n    // Start the local node up\n    await setupAnvilLocalNode(ethereumNode.nodeUrl);\n  }\n\n  // Initialize database.\n  await startDb();\n  startupQueues(concurrency);\n  // verifierFailedSubmissionsWatcher();\n\n  if (usLocalNode) {\n    // Switch to local node.\n    ethereumNode.nodeUrl = LOCAL_NODE_URL;\n  }\n\n  console.log(`\n\n            \n  \n\n\n  \n                                                                                                                           \nMMMMMMMM               MMMMMMMM     OOOOOOOOO     MMMMMMMM               MMMMMMMM     OOOOOOOOO     KKKKKKKKK    KKKKKKK               AAA               \nM:::::::M             M:::::::M   OO:::::::::OO   M:::::::M             M:::::::M   OO:::::::::OO   K:::::::K    K:::::K              A:::A              \nM::::::::M           M::::::::M OO:::::::::::::OO M::::::::M           M::::::::M OO:::::::::::::OO K:::::::K    K:::::K             A:::::A             \nM:::::::::M         M:::::::::MO:::::::OOO:::::::OM:::::::::M         M:::::::::MO:::::::OOO:::::::OK:::::::K   K::::::K            A:::::::A            \nM::::::::::M       M::::::::::MO::::::O   O::::::OM::::::::::M       M::::::::::MO::::::O   O::::::OKK::::::K  K:::::KKK           A:::::::::A           \nM:::::::::::M     M:::::::::::MO:::::O     O:::::OM:::::::::::M     M:::::::::::MO:::::O     O:::::O  K:::::K K:::::K             A:::::A:::::A          \nM:::::::M::::M   M::::M:::::::MO:::::O     O:::::OM:::::::M::::M   M::::M:::::::MO:::::O     O:::::O  K::::::K:::::K             A:::::A A:::::A         \nM::::::M M::::M M::::M M::::::MO:::::O     O:::::OM::::::M M::::M M::::M M::::::MO:::::O     O:::::O  K:::::::::::K             A:::::A   A:::::A        \nM::::::M  M::::M::::M  M::::::MO:::::O     O:::::OM::::::M  M::::M::::M  M::::::MO:::::O     O:::::O  K:::::::::::K            A:::::A     A:::::A       \nM::::::M   M:::::::M   M::::::MO:::::O     O:::::OM::::::M   M:::::::M   M::::::MO:::::O     O:::::O  K::::::K:::::K          A:::::AAAAAAAAA:::::A      \nM::::::M    M:::::M    M::::::MO:::::O     O:::::OM::::::M    M:::::M    M::::::MO:::::O     O:::::O  K:::::K K:::::K        A:::::::::::::::::::::A     \nM::::::M     MMMMM     M::::::MO::::::O   O::::::OM::::::M     MMMMM     M::::::MO::::::O   O::::::OKK::::::K  K:::::KKK    A:::::AAAAAAAAAAAAA:::::A    \nM::::::M               M::::::MO:::::::OOO:::::::OM::::::M               M::::::MO:::::::OOO:::::::OK:::::::K   K::::::K   A:::::A             A:::::A   \nM::::::M               M::::::M OO:::::::::::::OO M::::::M               M::::::M OO:::::::::::::OO K:::::::K    K:::::K  A:::::A               A:::::A  \nM::::::M               M::::::M   OO:::::::::OO   M::::::M               M::::::M   OO:::::::::OO   K:::::::K    K:::::K A:::::A                 A:::::A \nMMMMMMMM               MMMMMMMM     OOOOOOOOO     MMMMMMMM               MMMMMMMM     OOOOOOOOO     KKKKKKKKK    KKKKKKKAAAAAAA                   AAAAAAA\n                                                                                                                                                                                                                                                                                 \n                                                                                                                           \n                                                                                                                           \n                                                                                                                           \n                                                                                                                           \n                                                                                                                           \n                                                                                                                           \n                                                   \n  `);\n};\n\nexport interface BulkDataAvailabilityTransactionsResponse {\n  next: string | null;\n  txIds: string[];\n}\n\n/**\n *  Get the bulk data availability transactions from bundlr\n * @param environment The environment to use.\n * @param deployment The deployment to use.\n * @param endCursor  The end cursor to use.\n * @param maxPulling The maximum number of pulling.\n */\nconst getBulkDataAvailabilityTransactions = async (\n  environment: Environment,\n  deployment: Deployment | undefined,\n  endCursor: string | null,\n  maxPulling: number\n): Promise<BulkDataAvailabilityTransactionsResponse | null> => {\n  const result: BulkDataAvailabilityTransactionsResponse | null = {\n    next: endCursor,\n    txIds: [],\n  };\n  let pullingCounter = 0;\n\n  do {\n    const response = await getDataAvailabilityTransactionsAPI(\n      environment,\n      deployment,\n      result.next,\n      DataAvailabilityTransactionsOrderTypes.ASC\n    );\n    if (response.edges.length === 0) {\n      break;\n    }\n\n    const txIds = response.edges.map((edge) => edge.node.id);\n\n    result.next = response.pageInfo.endCursor;\n    result.txIds.push(...txIds);\n    pullingCounter++;\n  } while (result.next && pullingCounter < maxPulling);\n\n  return result;\n};\n\n/**\n *  Process the transactions and do the proof checks\n * @param transactions The transactions\n * @param ethereumNode The ethereum node to use\n * @param concurrency The concurrency to use < this is how many TCP it will run at\n * @param usLocalNode If we are using the local node\n * @param stream The stream callback\n */\nconst processTransactions = async (\n  transactions: BulkDataAvailabilityTransactionsResponse,\n  ethereumNode: EthereumNode,\n  concurrency: number,\n  usLocalNode: boolean,\n  stream: StreamCallback | undefined\n): Promise<{ totalChecked: number; endCursor: string | null }> => {\n  const result = await checkDAProofsBatch(\n    transactions.txIds,\n    ethereumNode,\n    false,\n    concurrency,\n    usLocalNode,\n    stream\n  );\n\n  const retryTxids = result\n    .filter((c) => !c.success && shouldRetry(c.validatorError!))\n    .map((c) => c.txId);\n\n  if (retryTxids.length > 0) {\n    void retryCheckDAProofsQueue.enqueueWithDelay(\n      {\n        txIds: retryTxids,\n        ethereumNode,\n        stream,\n      },\n      30000\n    );\n  }\n\n  return {\n    totalChecked: result.length - retryTxids.length,\n    endCursor: transactions.next,\n  };\n};\n\nconst waitForNewSubmissions = async (lastCheckNothingFound: boolean): Promise<boolean> => {\n  if (!lastCheckNothingFound) {\n    consoleLogWithLensNodeFootprint(`waiting for new momoka transactions...`);\n  }\n  lastCheckNothingFound = true;\n  await sleep(100);\n  return lastCheckNothingFound;\n};\n\n/**\n * Starts the DA verifier node to watch for new data availability submissions and verify their proofs.\n * @param ethereumNode The Ethereum node to use for verification.\n * @param concurrency The concurrency to use < this is how many TCP it will run at\n * @param options An optional object containing options for the node.\n *                   - stream - A callback function to stream the validation results.\n *                   - resync - A boolean to indicate whether to sync from the head of the chain only.\n */\nexport const startDAVerifierNode = async (\n  ethereumNode: EthereumNode,\n  concurrency: number,\n  { stream, resync }: StartDAVerifierNodeOptions = {}\n): Promise<never> => {\n  consoleLogWithLensNodeFootprint('DA verification watcher started...');\n\n  // for now you cant turn this on!\n  // will move it to .env later when needed\n  const usLocalNode = false;\n\n  await startup(ethereumNode, concurrency, usLocalNode);\n  let endCursor: string | null = await getLastEndCursorDb();\n  let totalChecked: number = await getTotalCheckedCountDb();\n  let lastCheckNothingFound = false;\n\n  consoleLogWithLensNodeFootprint('started up..');\n\n  if (!resync) {\n    // try to find the last transactions and start syncing from there again\n    const lastTransaction = await getDataAvailabilityTransactionsAPI(\n      ethereumNode.environment,\n      ethereumNode.deployment,\n      null,\n      DataAvailabilityTransactionsOrderTypes.DESC,\n      1\n    );\n\n    if (lastTransaction.edges.length > 0) {\n      endCursor = lastTransaction.pageInfo.endCursor;\n      totalChecked = 0;\n    } else {\n      endCursor = null;\n    }\n  }\n\n  return await runForever(async () => {\n    try {\n      // fetch 10,000 at a time! we can extend this if we wish for now thats plenty.\n      const transactions = await getBulkDataAvailabilityTransactions(\n        ethereumNode.environment,\n        ethereumNode.deployment,\n        endCursor,\n        10\n      );\n\n      if (!transactions || transactions.txIds.length === 0) {\n        lastCheckNothingFound = await waitForNewSubmissions(lastCheckNothingFound);\n      } else {\n        // count++;\n        lastCheckNothingFound = false;\n\n        if (resync) {\n          consoleLogWithLensNodeFootprint(`Resyncing momoka from start, preparing please wait...`);\n          resync = false;\n        }\n\n        const { totalChecked: newTotalChecked, endCursor: newEndCursor } =\n          await processTransactions(transactions, ethereumNode, concurrency, usLocalNode, stream);\n\n        totalChecked += newTotalChecked;\n        endCursor = newEndCursor;\n\n        await Promise.all([saveEndCursorDb(endCursor!), saveTotalCheckedCountDb(totalChecked)]);\n      }\n    } catch (error: unknown) {\n      const message = (error as Error).message || error;\n      consoleLogWithLensNodeFootprint('Error while checking for new submissions', message);\n      await sleep(100);\n    }\n  });\n};\n"
  },
  {
    "path": "momoka-node/src/workers/handler-communication.worker.ts",
    "content": "import { parentPort } from 'worker_threads';\nimport {\n  bundlrVerifyReceiptWorker,\n  BundlrVerifyReceiptWorkerRequest,\n  evmVerifyMessageWorker,\n  EVMVerifyMessageWorkerRequest,\n} from './message-handlers';\n\nexport type EVMVerifyMessageHandlerWorkerRequest = HandlerWorkerRequest<\n  HandlerWorkers.EVM_VERIFY_MESSAGE,\n  EVMVerifyMessageWorkerRequest\n>;\n\nexport type BundlrVerifyReceiptHandlerWorkerRequest = HandlerWorkerRequest<\n  HandlerWorkers.BUNDLR_VERIFY_RECEIPT,\n  BundlrVerifyReceiptWorkerRequest\n>;\n\nexport enum HandlerWorkers {\n  EVM_VERIFY_MESSAGE = 'EVM_VERIFY_MESSAGE',\n  BUNDLR_VERIFY_RECEIPT = 'BUNDLR_VERIFY_RECEIPT',\n}\n\nexport interface HandlerWorkerRequest<THandlerWorkers extends HandlerWorkers, T> {\n  worker: THandlerWorkers;\n  data: T;\n}\n\nexport type HandlerWorkerData =\n  | EVMVerifyMessageHandlerWorkerRequest\n  | BundlrVerifyReceiptHandlerWorkerRequest;\n\nconst executeWorker = async (request: HandlerWorkerData): Promise<string | boolean> => {\n  switch (request.worker) {\n    case HandlerWorkers.EVM_VERIFY_MESSAGE:\n      return await Promise.resolve(\n        evmVerifyMessageWorker(request.data as EVMVerifyMessageWorkerRequest)\n      );\n    case HandlerWorkers.BUNDLR_VERIFY_RECEIPT:\n      return await bundlrVerifyReceiptWorker(request.data as BundlrVerifyReceiptWorkerRequest);\n  }\n};\n\n// eslint-disable-next-line require-await\nparentPort?.on('message', async (request: string) => {\n  const handlerWorkerData = JSON.parse(request) as HandlerWorkerData;\n  const result = await executeWorker(handlerWorkerData);\n\n  parentPort!.postMessage(result);\n});\n"
  },
  {
    "path": "momoka-node/src/workers/message-handlers/bundlr-verify-receipt.worker.ts",
    "content": "import deepHash from 'arweave/node/lib/deepHash';\nimport Arweave from 'arweave/node';\nimport { b64UrlToBuffer } from 'arweave/node/lib/utils';\n\nimport { BundlrUploadResponse } from '../../data-availability-models/data-availability-timestamp-proofs';\nimport { verifyReceipt } from '../../proofs/utils';\n\nexport interface BundlrVerifyReceiptWorkerRequest {\n  bundlrUploadResponse: BundlrUploadResponse;\n}\n\n/**\n *  Verifies the receipt of a Bundlr upload\n * @param request - The request to verify the receipt of a Bundlr upload\n */\nexport const bundlrVerifyReceiptWorker = (\n  request: BundlrVerifyReceiptWorkerRequest\n): Promise<boolean> => {\n  return verifyReceipt(request.bundlrUploadResponse, {\n    crypto: Arweave.crypto,\n    deepHash,\n    b64UrlToBuffer,\n    stringToBuffer: Arweave.utils.stringToBuffer,\n  });\n};\n"
  },
  {
    "path": "momoka-node/src/workers/message-handlers/evm-verify-message.worker.ts",
    "content": "import { utils } from 'ethers';\nimport {\n  DAEventType,\n  DAStructurePublication,\n  PublicationTypedData,\n} from '../../data-availability-models/publications/data-availability-structure-publication';\n\nexport interface EVMVerifyMessageWorkerRequest {\n  daPublication: DAStructurePublication<DAEventType, PublicationTypedData>;\n  signature: string;\n}\n\n/**\n *  Verifies the signature of a message\n * @param request - The request to verify the signature of a message\n */\nexport const evmVerifyMessageWorker = (request: EVMVerifyMessageWorkerRequest): string => {\n  return utils.verifyMessage(JSON.stringify(request.daPublication), request.signature);\n};\n"
  },
  {
    "path": "momoka-node/src/workers/message-handlers/index.ts",
    "content": "export * from './bundlr-verify-receipt.worker';\nexport * from './evm-verify-message.worker';\n"
  },
  {
    "path": "momoka-node/src/workers/worker-pool.ts",
    "content": "import { cpus } from 'os';\nimport { resolve as resolvePath } from 'path';\nimport { Worker } from 'worker_threads';\nimport { HandlerWorkerData } from './handler-communication.worker';\n\n// const workerPath = resolvePath(__dirname, 'handler-communication.worker.js');\n\nclass WorkerPool {\n  private workers: Worker[] = [];\n  private queue: (() => void)[] = [];\n\n  constructor() {\n    // Set the pool size to the number of available CPU cores\n    const size = cpus().length;\n    for (let i = 0; i < size; i++) {\n      const worker = new Worker(\n        // worker path has to be a raw `.js` file so rewrite to `lib`\n        resolvePath(__dirname, '..', '..', 'lib', 'workers', 'handler-communication.worker.js')\n      );\n      worker.on('message', (_result) => {\n        this.queue.shift()?.();\n      });\n      this.workers.push(worker);\n    }\n  }\n\n  public execute<T>(request: HandlerWorkerData): Promise<T> {\n    const availableWorker = this.workers.shift();\n    if (!availableWorker) {\n      return new Promise((resolve) => {\n        this.queue.push(() => resolve(this.execute(request)));\n      });\n    }\n\n    return new Promise((resolve, _reject) => {\n      availableWorker.once('message', (result) => {\n        resolve(result);\n        this.workers.push(availableWorker);\n        this.queue.shift()?.();\n      });\n\n      availableWorker.postMessage(JSON.stringify(request));\n    });\n  }\n}\n\nexport const workerPool = new WorkerPool();\n"
  },
  {
    "path": "momoka-node/tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"target\": \"es2020\",\n    \"module\": \"commonjs\",\n    \"rootDir\": \"src\",\n    \"outDir\": \"lib\",\n    \"esModuleInterop\": true,\n    \"forceConsistentCasingInFileNames\": true,\n    \"strict\": true,\n    \"declaration\": true,\n    \"noUnusedLocals\": true,\n    \"noUnusedParameters\": true,\n    \"emitDecoratorMetadata\": true,\n    \"experimentalDecorators\": true,\n    \"noImplicitReturns\": true,\n    \"allowSyntheticDefaultImports\": true,\n    \"resolveJsonModule\": true,\n    \"sourceMap\": true\n  },\n  \"include\": [\"./src\"],\n  \"exclude\": [\"./src/__TESTS__\"]\n}\n"
  },
  {
    "path": "momoka-rs/Cargo.toml",
    "content": "[package]\nname = \"momoka\"\nversion = \"1.1.0\"\nedition = \"2021\"\nauthors = [\"Josh Stevens <josh@aave.io>\"]\ndescription = \"The momoka rs client\"\nlicense = \"MIT\"\nrepository = \"https://github.com/lens-protocol/momoka\"\n\n[dependencies]\ntokio = { version = \"1\", features = [\"full\"] }\nserde_json = \"1.0\"\ngql_client = \"1.0.7\"\nreqwest = \"0.11.4\"\nserde = { version = \"1.0\", features = [\"derive\"] }\nbase64 = \"0.21.0\"\nethers = \"2.0.4\"\nclap = { version = \"4.2.5\", features = [\"derive\"] }\nfutures = \"0.3\"\nasync-trait = \"0.1.51\"\nlazy_static = \"1.4.0\"\nbundlr-sdk = \"0.4.1\"\nregex = \"1.5\"\njson = \"0.12\"\nchrono = \"0.4\"\nstrum = \"0.24.1\"\nstrum_macros = \"0.24.3\"\ndata-encoding = \"2.3.0\"\nuuid = { version = \"1.3.2\", features = [\"v4\", \"serde\"] }\nhex = \"0.4.3\"\n\n[profile.performance]\ninherits = \"release\"\nlto = \"fat\"\ncodegen-units = 1\nincremental = false\n\n[target.'cfg(all(not(windows), not(target_env = \"musl\")))'.dependencies]\njemallocator = \"0.5.0\""
  },
  {
    "path": "momoka-rs/README.md",
    "content": "# momoka_rs\n\nTHIS ONLY SUPPORTS LENS V1 PUBLICATIONS AND HAS NOT BEEN MIGRATED TO LENS V2 SUPPORT YET.\n\nThis is the rust implementation of the momoka library. It is currently beta and still recommended you use the momoka-node for now. The rust library will be the main client in the future, the node and client verifier logic will always be supported and maintained so people can verify client side.\n\n## Installing\n\n```bash\n$ cargo install momoka\n```\n\n## CLI\n\nUsage: momoka [OPTIONS]\n\n```bash\nOptions:\n  -n <NODE>             The URL of the node\n  -e <ENVIRONMENT>      The environment (e.g., \"MUMBAI\", \"AMOY\" or \"POLYGON\")\n  -d <DEPLOYMENT>       The deployment (e.g., \"PRODUCTION\")\n  -t <TX_ID>            The transaction ID to check proof for\n  -r                    Flag indicating whether to perform a resync\n  -h, --help            Print help\n  -V, --version         Print version\n```\n\n## Usage CLI\n\nIt is easy to run the momoka verifier locally using cargo. You can do so by running the following commands:\n\n### Verifying live transactions\n\n```bash\n$ momoka\n```\n\nNote if you do not supply a `-n=\"YOUR_NODE\"` it will use a free node which has very low rate limits. If using it for anything in production you should supply your own node.\n\nThis will start verifying any incoming momoka transactions live. You can also can specify to resync from transaction 1 by adding the `-r` flag (this needs a node which is paid and has a high rate limit).\n\n### Verifying a single transaction\n\n```bash\n$ momoka -t=\"TX_ID\"\n```\n\n### Running locally from source\n\nIt is easy to run the momoka verifier locally using cargo. You can do so by running the following command:\n\n```bash\n$ cargo run -- -n=\"YOUR_NODE\" [-r] [-t=\"TX_ID\"]\n```\n"
  },
  {
    "path": "momoka-rs/src/abi/lens_hub_contract_abi.json",
    "content": "[\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"followNFTImpl\", \"type\": \"address\" },\n      { \"internalType\": \"address\", \"name\": \"collectNFTImpl\", \"type\": \"address\" }\n    ],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"constructor\"\n  },\n  { \"inputs\": [], \"name\": \"CallerNotCollectNFT\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"CallerNotFollowNFT\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"CannotInitImplementation\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"DispatcherNotSet\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"EmergencyAdminCannotUnpause\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"InitParamsInvalid\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"Initialized\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"NotGovernance\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"NotGovernanceOrEmergencyAdmin\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"NotOwnerOrApproved\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"NotProfileOwner\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"NotProfileOwnerOrDispatcher\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"Paused\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"ProfileCreatorNotWhitelisted\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"ProfileImageURILengthInvalid\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"PublicationDoesNotExist\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"PublishingPaused\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"SignatureExpired\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"SignatureInvalid\", \"type\": \"error\" },\n  { \"inputs\": [], \"name\": \"ZeroSpender\", \"type\": \"error\" },\n  {\n    \"anonymous\": false,\n    \"inputs\": [\n      { \"indexed\": true, \"internalType\": \"address\", \"name\": \"owner\", \"type\": \"address\" },\n      { \"indexed\": true, \"internalType\": \"address\", \"name\": \"approved\", \"type\": \"address\" },\n      { \"indexed\": true, \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"Approval\",\n    \"type\": \"event\"\n  },\n  {\n    \"anonymous\": false,\n    \"inputs\": [\n      { \"indexed\": true, \"internalType\": \"address\", \"name\": \"owner\", \"type\": \"address\" },\n      { \"indexed\": true, \"internalType\": \"address\", \"name\": \"operator\", \"type\": \"address\" },\n      { \"indexed\": false, \"internalType\": \"bool\", \"name\": \"approved\", \"type\": \"bool\" }\n    ],\n    \"name\": \"ApprovalForAll\",\n    \"type\": \"event\"\n  },\n  {\n    \"anonymous\": false,\n    \"inputs\": [\n      { \"indexed\": true, \"internalType\": \"address\", \"name\": \"from\", \"type\": \"address\" },\n      { \"indexed\": true, \"internalType\": \"address\", \"name\": \"to\", \"type\": \"address\" },\n      { \"indexed\": true, \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"Transfer\",\n    \"type\": \"event\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"to\", \"type\": \"address\" },\n      { \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"approve\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"address\", \"name\": \"owner\", \"type\": \"address\" }],\n    \"name\": \"balanceOf\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }],\n    \"name\": \"burn\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" },\n      {\n        \"components\": [\n          { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n          { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n          { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n          { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n        ],\n        \"internalType\": \"struct DataTypes.EIP712Signature\",\n        \"name\": \"sig\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"burnWithSig\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"pubId\", \"type\": \"uint256\" },\n      { \"internalType\": \"bytes\", \"name\": \"data\", \"type\": \"bytes\" }\n    ],\n    \"name\": \"collect\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"address\", \"name\": \"collector\", \"type\": \"address\" },\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"uint256\", \"name\": \"pubId\", \"type\": \"uint256\" },\n          { \"internalType\": \"bytes\", \"name\": \"data\", \"type\": \"bytes\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.CollectWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"collectWithSig\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"string\", \"name\": \"contentURI\", \"type\": \"string\" },\n          { \"internalType\": \"uint256\", \"name\": \"profileIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"uint256\", \"name\": \"pubIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"collectModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"collectModuleInitData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleInitData\", \"type\": \"bytes\" }\n        ],\n        \"internalType\": \"struct DataTypes.CommentData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"comment\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"string\", \"name\": \"contentURI\", \"type\": \"string\" },\n          { \"internalType\": \"uint256\", \"name\": \"profileIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"uint256\", \"name\": \"pubIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"collectModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"collectModuleInitData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleInitData\", \"type\": \"bytes\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.CommentWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"commentWithSig\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"string\", \"name\": \"contentURI\", \"type\": \"string\" },\n          { \"internalType\": \"uint256\", \"name\": \"profileIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"uint256\", \"name\": \"pubIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"collectModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"collectModuleInitData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleInitData\", \"type\": \"bytes\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.CommentWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"commentWithSig_Dispatcher\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"address\", \"name\": \"to\", \"type\": \"address\" },\n          { \"internalType\": \"string\", \"name\": \"handle\", \"type\": \"string\" },\n          { \"internalType\": \"string\", \"name\": \"imageURI\", \"type\": \"string\" },\n          { \"internalType\": \"address\", \"name\": \"followModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"followModuleInitData\", \"type\": \"bytes\" },\n          { \"internalType\": \"string\", \"name\": \"followNFTURI\", \"type\": \"string\" }\n        ],\n        \"internalType\": \"struct DataTypes.CreateProfileData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"createProfile\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"address\", \"name\": \"wallet\", \"type\": \"address\" }],\n    \"name\": \"defaultProfile\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"pubId\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"collectNFTId\", \"type\": \"uint256\" },\n      { \"internalType\": \"address\", \"name\": \"from\", \"type\": \"address\" },\n      { \"internalType\": \"address\", \"name\": \"to\", \"type\": \"address\" }\n    ],\n    \"name\": \"emitCollectNFTTransferEvent\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"followNFTId\", \"type\": \"uint256\" },\n      { \"internalType\": \"address\", \"name\": \"from\", \"type\": \"address\" },\n      { \"internalType\": \"address\", \"name\": \"to\", \"type\": \"address\" }\n    ],\n    \"name\": \"emitFollowNFTTransferEvent\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }],\n    \"name\": \"exists\",\n    \"outputs\": [{ \"internalType\": \"bool\", \"name\": \"\", \"type\": \"bool\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256[]\", \"name\": \"profileIds\", \"type\": \"uint256[]\" },\n      { \"internalType\": \"bytes[]\", \"name\": \"datas\", \"type\": \"bytes[]\" }\n    ],\n    \"name\": \"follow\",\n    \"outputs\": [{ \"internalType\": \"uint256[]\", \"name\": \"\", \"type\": \"uint256[]\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"address\", \"name\": \"follower\", \"type\": \"address\" },\n          { \"internalType\": \"uint256[]\", \"name\": \"profileIds\", \"type\": \"uint256[]\" },\n          { \"internalType\": \"bytes[]\", \"name\": \"datas\", \"type\": \"bytes[]\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.FollowWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"followWithSig\",\n    \"outputs\": [{ \"internalType\": \"uint256[]\", \"name\": \"\", \"type\": \"uint256[]\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }],\n    \"name\": \"getApproved\",\n    \"outputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"pubId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"getCollectModule\",\n    \"outputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"pubId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"getCollectNFT\",\n    \"outputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [],\n    \"name\": \"getCollectNFTImpl\",\n    \"outputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"pubId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"getContentURI\",\n    \"outputs\": [{ \"internalType\": \"string\", \"name\": \"\", \"type\": \"string\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" }],\n    \"name\": \"getDispatcher\",\n    \"outputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [],\n    \"name\": \"getDomainSeparator\",\n    \"outputs\": [{ \"internalType\": \"bytes32\", \"name\": \"\", \"type\": \"bytes32\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" }],\n    \"name\": \"getFollowModule\",\n    \"outputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" }],\n    \"name\": \"getFollowNFT\",\n    \"outputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [],\n    \"name\": \"getFollowNFTImpl\",\n    \"outputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" }],\n    \"name\": \"getFollowNFTURI\",\n    \"outputs\": [{ \"internalType\": \"string\", \"name\": \"\", \"type\": \"string\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [],\n    \"name\": \"getGovernance\",\n    \"outputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" }],\n    \"name\": \"getHandle\",\n    \"outputs\": [{ \"internalType\": \"string\", \"name\": \"\", \"type\": \"string\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" }],\n    \"name\": \"getProfile\",\n    \"outputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"pubCount\", \"type\": \"uint256\" },\n          { \"internalType\": \"address\", \"name\": \"followModule\", \"type\": \"address\" },\n          { \"internalType\": \"address\", \"name\": \"followNFT\", \"type\": \"address\" },\n          { \"internalType\": \"string\", \"name\": \"handle\", \"type\": \"string\" },\n          { \"internalType\": \"string\", \"name\": \"imageURI\", \"type\": \"string\" },\n          { \"internalType\": \"string\", \"name\": \"followNFTURI\", \"type\": \"string\" }\n        ],\n        \"internalType\": \"struct DataTypes.ProfileStruct\",\n        \"name\": \"\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"string\", \"name\": \"handle\", \"type\": \"string\" }],\n    \"name\": \"getProfileIdByHandle\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"pubId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"getPub\",\n    \"outputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"uint256\", \"name\": \"pubIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"string\", \"name\": \"contentURI\", \"type\": \"string\" },\n          { \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" },\n          { \"internalType\": \"address\", \"name\": \"collectModule\", \"type\": \"address\" },\n          { \"internalType\": \"address\", \"name\": \"collectNFT\", \"type\": \"address\" }\n        ],\n        \"internalType\": \"struct DataTypes.PublicationStruct\",\n        \"name\": \"\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" }],\n    \"name\": \"getPubCount\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"pubId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"getPubPointer\",\n    \"outputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }\n    ],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"pubId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"getPubType\",\n    \"outputs\": [{ \"internalType\": \"enum DataTypes.PubType\", \"name\": \"\", \"type\": \"uint8\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"uint256\", \"name\": \"pubId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"getReferenceModule\",\n    \"outputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [],\n    \"name\": \"getState\",\n    \"outputs\": [{ \"internalType\": \"enum DataTypes.ProtocolState\", \"name\": \"\", \"type\": \"uint8\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"string\", \"name\": \"name\", \"type\": \"string\" },\n      { \"internalType\": \"string\", \"name\": \"symbol\", \"type\": \"string\" },\n      { \"internalType\": \"address\", \"name\": \"newGovernance\", \"type\": \"address\" }\n    ],\n    \"name\": \"initialize\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"owner\", \"type\": \"address\" },\n      { \"internalType\": \"address\", \"name\": \"operator\", \"type\": \"address\" }\n    ],\n    \"name\": \"isApprovedForAll\",\n    \"outputs\": [{ \"internalType\": \"bool\", \"name\": \"\", \"type\": \"bool\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"address\", \"name\": \"collectModule\", \"type\": \"address\" }],\n    \"name\": \"isCollectModuleWhitelisted\",\n    \"outputs\": [{ \"internalType\": \"bool\", \"name\": \"\", \"type\": \"bool\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"address\", \"name\": \"followModule\", \"type\": \"address\" }],\n    \"name\": \"isFollowModuleWhitelisted\",\n    \"outputs\": [{ \"internalType\": \"bool\", \"name\": \"\", \"type\": \"bool\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"address\", \"name\": \"profileCreator\", \"type\": \"address\" }],\n    \"name\": \"isProfileCreatorWhitelisted\",\n    \"outputs\": [{ \"internalType\": \"bool\", \"name\": \"\", \"type\": \"bool\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" }],\n    \"name\": \"isReferenceModuleWhitelisted\",\n    \"outputs\": [{ \"internalType\": \"bool\", \"name\": \"\", \"type\": \"bool\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }],\n    \"name\": \"mintTimestampOf\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"uint256\", \"name\": \"profileIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"uint256\", \"name\": \"pubIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleInitData\", \"type\": \"bytes\" }\n        ],\n        \"internalType\": \"struct DataTypes.MirrorData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"mirror\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"uint256\", \"name\": \"profileIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"uint256\", \"name\": \"pubIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleInitData\", \"type\": \"bytes\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.MirrorWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"mirrorWithSig\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"uint256\", \"name\": \"profileIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"uint256\", \"name\": \"pubIdPointed\", \"type\": \"uint256\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleInitData\", \"type\": \"bytes\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.MirrorWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"mirrorWithSig_Dispatcher\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [],\n    \"name\": \"name\",\n    \"outputs\": [{ \"internalType\": \"string\", \"name\": \"\", \"type\": \"string\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }],\n    \"name\": \"ownerOf\",\n    \"outputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"spender\", \"type\": \"address\" },\n      { \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" },\n      {\n        \"components\": [\n          { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n          { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n          { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n          { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n        ],\n        \"internalType\": \"struct DataTypes.EIP712Signature\",\n        \"name\": \"sig\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"permit\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"owner\", \"type\": \"address\" },\n      { \"internalType\": \"address\", \"name\": \"operator\", \"type\": \"address\" },\n      { \"internalType\": \"bool\", \"name\": \"approved\", \"type\": \"bool\" },\n      {\n        \"components\": [\n          { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n          { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n          { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n          { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n        ],\n        \"internalType\": \"struct DataTypes.EIP712Signature\",\n        \"name\": \"sig\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"permitForAll\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"string\", \"name\": \"contentURI\", \"type\": \"string\" },\n          { \"internalType\": \"address\", \"name\": \"collectModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"collectModuleInitData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleInitData\", \"type\": \"bytes\" }\n        ],\n        \"internalType\": \"struct DataTypes.PostData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"post\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"string\", \"name\": \"contentURI\", \"type\": \"string\" },\n          { \"internalType\": \"address\", \"name\": \"collectModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"collectModuleInitData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleInitData\", \"type\": \"bytes\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.PostWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"postWithSig\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"string\", \"name\": \"contentURI\", \"type\": \"string\" },\n          { \"internalType\": \"address\", \"name\": \"collectModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"collectModuleInitData\", \"type\": \"bytes\" },\n          { \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"referenceModuleInitData\", \"type\": \"bytes\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.PostWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"postWithSig_Dispatcher\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"from\", \"type\": \"address\" },\n      { \"internalType\": \"address\", \"name\": \"to\", \"type\": \"address\" },\n      { \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"safeTransferFrom\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"from\", \"type\": \"address\" },\n      { \"internalType\": \"address\", \"name\": \"to\", \"type\": \"address\" },\n      { \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" },\n      { \"internalType\": \"bytes\", \"name\": \"_data\", \"type\": \"bytes\" }\n    ],\n    \"name\": \"safeTransferFrom\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"operator\", \"type\": \"address\" },\n      { \"internalType\": \"bool\", \"name\": \"approved\", \"type\": \"bool\" }\n    ],\n    \"name\": \"setApprovalForAll\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" }],\n    \"name\": \"setDefaultProfile\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"address\", \"name\": \"wallet\", \"type\": \"address\" },\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.SetDefaultProfileWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"setDefaultProfileWithSig\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"address\", \"name\": \"dispatcher\", \"type\": \"address\" }\n    ],\n    \"name\": \"setDispatcher\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"address\", \"name\": \"dispatcher\", \"type\": \"address\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.SetDispatcherWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"setDispatcherWithSig\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"address\", \"name\": \"newEmergencyAdmin\", \"type\": \"address\" }],\n    \"name\": \"setEmergencyAdmin\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"address\", \"name\": \"followModule\", \"type\": \"address\" },\n      { \"internalType\": \"bytes\", \"name\": \"followModuleInitData\", \"type\": \"bytes\" }\n    ],\n    \"name\": \"setFollowModule\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"address\", \"name\": \"followModule\", \"type\": \"address\" },\n          { \"internalType\": \"bytes\", \"name\": \"followModuleInitData\", \"type\": \"bytes\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.SetFollowModuleWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"setFollowModuleWithSig\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"string\", \"name\": \"followNFTURI\", \"type\": \"string\" }\n    ],\n    \"name\": \"setFollowNFTURI\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"string\", \"name\": \"followNFTURI\", \"type\": \"string\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.SetFollowNFTURIWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"setFollowNFTURIWithSig\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"address\", \"name\": \"newGovernance\", \"type\": \"address\" }],\n    \"name\": \"setGovernance\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n      { \"internalType\": \"string\", \"name\": \"imageURI\", \"type\": \"string\" }\n    ],\n    \"name\": \"setProfileImageURI\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"uint256\", \"name\": \"profileId\", \"type\": \"uint256\" },\n          { \"internalType\": \"string\", \"name\": \"imageURI\", \"type\": \"string\" },\n          {\n            \"components\": [\n              { \"internalType\": \"uint8\", \"name\": \"v\", \"type\": \"uint8\" },\n              { \"internalType\": \"bytes32\", \"name\": \"r\", \"type\": \"bytes32\" },\n              { \"internalType\": \"bytes32\", \"name\": \"s\", \"type\": \"bytes32\" },\n              { \"internalType\": \"uint256\", \"name\": \"deadline\", \"type\": \"uint256\" }\n            ],\n            \"internalType\": \"struct DataTypes.EIP712Signature\",\n            \"name\": \"sig\",\n            \"type\": \"tuple\"\n          }\n        ],\n        \"internalType\": \"struct DataTypes.SetProfileImageURIWithSigData\",\n        \"name\": \"vars\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"name\": \"setProfileImageURIWithSig\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"enum DataTypes.ProtocolState\", \"name\": \"newState\", \"type\": \"uint8\" }\n    ],\n    \"name\": \"setState\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"address\", \"name\": \"\", \"type\": \"address\" }],\n    \"name\": \"sigNonces\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"bytes4\", \"name\": \"interfaceId\", \"type\": \"bytes4\" }],\n    \"name\": \"supportsInterface\",\n    \"outputs\": [{ \"internalType\": \"bool\", \"name\": \"\", \"type\": \"bool\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [],\n    \"name\": \"symbol\",\n    \"outputs\": [{ \"internalType\": \"string\", \"name\": \"\", \"type\": \"string\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"index\", \"type\": \"uint256\" }],\n    \"name\": \"tokenByIndex\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }],\n    \"name\": \"tokenDataOf\",\n    \"outputs\": [\n      {\n        \"components\": [\n          { \"internalType\": \"address\", \"name\": \"owner\", \"type\": \"address\" },\n          { \"internalType\": \"uint96\", \"name\": \"mintTimestamp\", \"type\": \"uint96\" }\n        ],\n        \"internalType\": \"struct IERC721Time.TokenData\",\n        \"name\": \"\",\n        \"type\": \"tuple\"\n      }\n    ],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"owner\", \"type\": \"address\" },\n      { \"internalType\": \"uint256\", \"name\": \"index\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"tokenOfOwnerByIndex\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [{ \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }],\n    \"name\": \"tokenURI\",\n    \"outputs\": [{ \"internalType\": \"string\", \"name\": \"\", \"type\": \"string\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [],\n    \"name\": \"totalSupply\",\n    \"outputs\": [{ \"internalType\": \"uint256\", \"name\": \"\", \"type\": \"uint256\" }],\n    \"stateMutability\": \"view\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"from\", \"type\": \"address\" },\n      { \"internalType\": \"address\", \"name\": \"to\", \"type\": \"address\" },\n      { \"internalType\": \"uint256\", \"name\": \"tokenId\", \"type\": \"uint256\" }\n    ],\n    \"name\": \"transferFrom\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"collectModule\", \"type\": \"address\" },\n      { \"internalType\": \"bool\", \"name\": \"whitelist\", \"type\": \"bool\" }\n    ],\n    \"name\": \"whitelistCollectModule\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"followModule\", \"type\": \"address\" },\n      { \"internalType\": \"bool\", \"name\": \"whitelist\", \"type\": \"bool\" }\n    ],\n    \"name\": \"whitelistFollowModule\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"profileCreator\", \"type\": \"address\" },\n      { \"internalType\": \"bool\", \"name\": \"whitelist\", \"type\": \"bool\" }\n    ],\n    \"name\": \"whitelistProfileCreator\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  },\n  {\n    \"inputs\": [\n      { \"internalType\": \"address\", \"name\": \"referenceModule\", \"type\": \"address\" },\n      { \"internalType\": \"bool\", \"name\": \"whitelist\", \"type\": \"bool\" }\n    ],\n    \"name\": \"whitelistReferenceModule\",\n    \"outputs\": [],\n    \"stateMutability\": \"nonpayable\",\n    \"type\": \"function\"\n  }\n]\n"
  },
  {
    "path": "momoka-rs/src/bundlr/api.rs",
    "content": "use crate::{\n    environment::{Deployment, Environment},\n    http::post_with_timeout,\n    submitter::state::get_submitters,\n    types::{\n        transaction::{\n            MomokaTransaction, MomokaTransactionName, MomokaTxId, TimestampProofsResponse,\n            TimestampProofsSummary, TransactionError, TransactionSummary,\n        },\n        verifier_error::MomokaVerifierError,\n    },\n};\nuse base64::{engine::general_purpose, Engine};\nuse ethers::{types::Address, utils};\nuse gql_client::Client;\nuse serde::{Deserialize, Serialize};\nuse std::{collections::HashMap, str::FromStr};\n\n/// An enum representing various Bundlr endpoints.\nenum BundlrEndpoint {\n    GraphQl,\n    BulkTxsData,\n}\n\nimpl BundlrEndpoint {\n    /// Get the URL of the endpoint.\n    ///\n    /// # Returns\n    ///\n    /// * A string slice containing the URL of the endpoint.\n    pub fn url(&self) -> &str {\n        match self {\n            BundlrEndpoint::GraphQl => \"https://lens.bundlr.network/graphql\",\n            BundlrEndpoint::BulkTxsData => \"https://lens.bundlr.network/bulk/txs/data\",\n        }\n    }\n}\n\n/// A bundlr transaction.\n///\n/// This struct holds the edges and page information of the momoka transactiond\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct BundlrTransactions {\n    /// The edges of the bundlr transaction\n    pub edges: Vec<BundlrTransactionEdge>,\n\n    /// The page information of the bundlr transaction\n    #[serde(rename = \"pageInfo\")]\n    pub page_info: BundlrTransactionPageInfo,\n}\n\n/// A bundlr edge transaction.\n///\n/// This struct holds the edges and page information of the momoka transactiond\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct BundlrTransactionEdge {\n    /// The node of the bundlr transaction (this is the address which did the action)\n    pub node: BundlrTransactionNode,\n\n    /// The cursor of the bundlr transaction\n    pub cursor: String,\n}\n\n/// A bundlr node transaction.\n///\n/// This struct holds the node transaction information\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct BundlrTransactionNode {\n    /// The id of the bundlr transaction\n    pub id: String,\n\n    /// The address of the bundlr transaction\n    pub address: String,\n}\n\n/// A bundlr transaction page information.\n///\n/// This struct holds the page information of the bundlr transaction\n/// and information allowing you to go to the next page\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct BundlrTransactionPageInfo {\n    /// If their is more transactions\n    #[serde(rename = \"hasNextPage\")]\n    pub has_next_page: bool,\n\n    /// The end cursor of the bundlr transactions for this page\n    #[serde(rename = \"endCursor\")]\n    pub end_cursor: Option<String>,\n}\n\n/// API response for getting momoka transactions from Bundlr.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct TransactionsAPIResponse {\n    pub transactions: BundlrTransactions,\n}\n\n/// Represents the order direction for sorting.\n#[derive(Debug, Clone, Copy)]\npub enum TransactionOrder {\n    Ascending,\n    Descending,\n}\n\n/// Constructs the GraphQL query to fetch data availability transactions.\n///\n/// # Arguments\n///\n/// * `owners` - A vector of addresses representing the owners to query transactions for.\n/// * `limit` - The maximum number of transactions to retrieve.\n/// * `after` - An optional cursor indicating the starting point for pagination.\n///\n/// # Returns\n///\n/// The constructed GraphQL query as a string.\nfn get_transactions_query(\n    owners: Vec<Address>,\n    limit: i32,\n    after: &Option<String>,\n    order: TransactionOrder,\n) -> String {\n    let after_value = match after {\n        Some(value) => format!(\"\\\"{}\\\"\", value),\n        None => \"null\".to_string(),\n    };\n\n    let order_value = match order {\n        TransactionOrder::Ascending => \"ASC\",\n        TransactionOrder::Descending => \"DESC\",\n    };\n\n    let owner_addresses: Vec<String> = owners\n        .iter()\n        .map(|address| utils::to_checksum(address, None))\n        .collect();\n\n    format!(\n        r#\"query DataAvailabilityTransactions {{\n            transactions(owners: {:?}, limit: {}, after: {}, order: {}, hasTags: true) {{\n                edges {{\n                    node {{\n                        id\n                        address\n                    }}\n                    cursor\n                }}\n                pageInfo {{\n                    endCursor\n                    hasNextPage\n                }}\n            }}\n        }}\"#,\n        owner_addresses, limit, after_value, order_value\n    )\n}\n\n/// Get transactions from bundlr\n///\n/// # Examples\n///\n/// ```\n/// let result = get_transactions_api(5);\n/// ```\npub async fn get_transactions_api(\n    environment: &Environment,\n    deployment: &Deployment,\n    limit: i32,\n    end_cursor: &Option<String>,\n    order: TransactionOrder,\n) -> Result<TransactionsAPIResponse, MomokaVerifierError> {\n    let submitters = get_submitters(environment, deployment);\n    let query = get_transactions_query(submitters, limit, end_cursor, order);\n\n    let client = Client::new(BundlrEndpoint::GraphQl.url());\n    let response = client\n        .query::<TransactionsAPIResponse>(&query)\n        .await\n        .map_err(|_e| MomokaVerifierError::CannotConnectToBundlr)?;\n\n    Ok(response.unwrap())\n}\n\n/// API response for grabbing bulk transactions from momoka.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct BulkTransactionsIdsAPIResponse {\n    pub next: Option<String>,\n    pub tx_ids: Vec<String>,\n}\n\n/// Retrieves the ID of the last transaction using the specified environment and deployment.\n///\n/// # Arguments\n///\n/// * `environment` - A reference to the `Environment` enum representing the environment.\n/// * `deployment` - A reference to the `Deployment` enum representing the deployment.\n///\n/// # Returns\n///\n/// A `Result` containing the ID of the last transaction as a `String` if successful, or a `MomokaVerifierError` if an error occurs.\npub async fn get_last_transaction_api(\n    environment: &Environment,\n    deployment: &Deployment,\n) -> Result<BundlrTransactionEdge, MomokaVerifierError> {\n    let response = get_transactions_api(\n        environment,\n        deployment,\n        1,\n        &None,\n        TransactionOrder::Descending,\n    )\n    .await?\n    .transactions;\n\n    let edge = response\n        .edges\n        .first()\n        .ok_or(MomokaVerifierError::NoLastTransactionFound)?;\n\n    // always the first one as we doing limit 1\n    Ok(edge.to_owned())\n}\n\n/// Retrieves a bulk of transaction ids from Momoka, up to a maximum number of pulls.\n///\n/// This function pulls transactions from Momoka until either the maximum number of pulls is reached,\n/// or there are no more transactions to pull. The result is returned as an optional bulk transactions\n/// API response, which contains the transaction IDs and a cursor for pagination.\n///\n/// # Arguments\n///\n/// * `environment` - The environment to use for the API request.\n/// * `deployment` - The deployment to use for the API request.\n/// * `end_cursor` - The cursor for pagination, indicating where to start pulling transactions from.\n/// * `max_pulling` - The maximum number of pulls to perform.\n///\n/// # Examples\n///\n/// ```\n/// let response = get_bulk_transactions_ids_api(Environment::Production, Deployment::Mainnet, None, 5).await.unwrap();\n/// assert_eq!(response.tx_ids.len(), 15);\n/// ```\npub async fn get_bulk_transactions_ids_api(\n    environment: &Environment,\n    deployment: &Deployment,\n    end_cursor: &Option<String>,\n    max_pulling: usize,\n) -> Result<Option<BulkTransactionsIdsAPIResponse>, MomokaVerifierError> {\n    let mut result = BulkTransactionsIdsAPIResponse {\n        next: end_cursor.clone(),\n        tx_ids: vec![],\n    };\n\n    for _ in 0..max_pulling {\n        let response = get_transactions_api(\n            environment,\n            deployment,\n            1000,\n            &result.next,\n            TransactionOrder::Ascending,\n        )\n        .await?\n        .transactions;\n\n        if response.edges.is_empty() {\n            break;\n        }\n\n        let tx_ids = response\n            .edges\n            .into_iter()\n            .map(|edge| edge.node.id)\n            .collect::<Vec<_>>();\n\n        result.next = response.page_info.end_cursor;\n        result.tx_ids.extend(tx_ids);\n\n        if result.next.is_none() {\n            break;\n        }\n    }\n\n    Ok(if result.tx_ids.is_empty() {\n        None\n    } else {\n        Some(result)\n    })\n}\n\n/// Bundlr transaction in base 64 format aka the data\n#[derive(Debug, Deserialize)]\npub struct BundlrTransactionBase64 {\n    pub id: String,\n    pub address: Address,\n    pub data: String,\n}\n\n/// Bundlr bulk transactions response\n#[derive(Debug, Deserialize)]\npub struct BundlrBulkTransactionsResponse<TSuccess> {\n    pub success: Vec<TSuccess>,\n    pub failed: std::collections::HashMap<MomokaTxId, MomokaVerifierError>,\n}\n\n/// Fetches a bulk set of transactions from the Bundlr node and returns the result as a `BundlrBulkTransactionsResponse` containing base64-encoded transaction data.\n///\n/// # Arguments\n///\n/// * `tx_ids` - A slice of `String` objects representing the IDs of the transactions to fetch.\n///\n/// # Errors\n///\n/// Returns a `MomokaVerifierError` if there is an error connecting to the Bundlr node or if the response is invalid.\n///\n/// # Examples\n///\n/// ```\n/// use crate::types::transaction::BundlrTransactionBase64;\n///\n/// let tx_ids = vec![\n///     \"PoDx9KfHCIKAdJg2WyfWcx2B_K5aMKq0je7EtIcOc4w\",\n///     \"HoDx9KfHCIKAdJg2WyfWcx2B_K5aMKq0je7EtIcOc4w\",\n///     \"LoDx9KfHCIKAdJg2WyfWcx2B_K5aMKq0je7EtIcOc4w\",\n/// ];\n///\n/// let response = get_bulk_transactions_base_64_api(&tx_ids).await?;\n///\n/// assert_eq!(response.transactions.len(), tx_ids.len());\n/// for tx in response.transactions {\n///     println!(\"Transaction: {:?}\", tx);\n/// }\n/// ```\nasync fn get_bulk_transactions_base_64_api(\n    tx_ids: &[String],\n) -> Result<BundlrBulkTransactionsResponse<BundlrTransactionBase64>, MomokaVerifierError> {\n    post_with_timeout(BundlrEndpoint::BulkTxsData.url(), &tx_ids.to_vec())\n        .await\n        .map_err(|_| MomokaVerifierError::CannotConnectToBundlr)\n}\n\n/// Decodes the base64-encoded `data` field of each `BundlrTransactionBase64`\n/// struct in the `results` vector, applies the provided closure to the decoded\n/// `String`, and collects the results into a vector of `TResult`.\n///\n/// # Arguments\n///\n/// * `results` - A vector of `BundlrTransactionBase64` structs to process.\n/// * `builder` - A closure that accepts a `String` argument and returns a `TResult`.\n///\n/// # Returns\n///\n/// A `Result` containing a vector of `TResult` if the decoding and processing was\n/// successful, or a `MomokaVerifierError` if an error occurred.\n///\n/// # Example\n///\n/// ```rust\n/// use my_crate::{from_base_64, BundlrTransactionBase64};\n///\n/// fn my_builder(s: &String) -> u32 {\n///     s.len() as u32\n/// }\n///\n/// let results = vec![\n///     BundlrTransactionBase64 { data: \"aGVsbG8=\".to_owned() },\n///     BundlrTransactionBase64 { data: \"d29ybGQ=\".to_owned() },\n/// ];\n///\n/// let res = from_base_64(results, my_builder);\n///\n/// assert_eq!(res.unwrap(), vec![5, 4]);\n/// ```\n///\nasync fn from_base_64<TResult>(\n    results: &Vec<BundlrTransactionBase64>,\n    builder: fn(&str, reference: &BundlrTransactionBase64) -> TResult,\n) -> Result<Vec<TResult>, MomokaVerifierError> {\n    let mut batch_result: Vec<TResult> = Vec::new();\n\n    let mut tasks = Vec::new();\n    for result in results {\n        let task = async move {\n            let decoded = general_purpose::STANDARD\n                .decode(&result.data)\n                .map_err(|_| MomokaVerifierError::InvalidTransactionFormat)?;\n\n            let transaction = String::from_utf8(decoded)\n                .map_err(|_| MomokaVerifierError::InvalidTransactionFormat)?;\n\n            let result = builder(&transaction, result);\n\n            Ok(result)\n        };\n\n        tasks.push(task);\n    }\n\n    let batch_results = futures::future::try_join_all(tasks).await?;\n\n    batch_result.extend(batch_results);\n\n    Ok(batch_result)\n}\n\n/// Constructs a `TransactionSummary` from a decoded transaction string and a `BundlrTransactionBase64` reference.\n///\n/// # Arguments\n///\n/// * `decoded_transaction` - A string containing the decoded transaction data.\n/// * `reference` - A `BundlrTransactionBase64` reference containing metadata about the transaction.\n///\n/// # Errors\n///\n/// Returns a `MomokaVerifierError` if the decoded transaction data is invalid or if there is an error\n/// parsing the transaction type from the JSON data.\n///\n/// # Returns\n///\n/// Returns a `TransactionSummary` struct containing information about the transaction.\n///\nfn transaction_builder(\n    decoded_transaction: &str,\n    reference: &BundlrTransactionBase64,\n) -> Result<TransactionSummary, TransactionError> {\n    // Parse the decoded transaction data into a JSON value.\n    let json_value: serde_json::Value =\n        serde_json::from_str(decoded_transaction).map_err(|_| {\n            TransactionError::new(\n                reference.id.clone(),\n                MomokaVerifierError::InvalidTransactionFormat,\n            )\n        })?;\n\n    // Get the transaction type from the JSON data and parse it into a `TransactionType` enum.\n    let transaction_type = MomokaTransaction::from_json(\n        decoded_transaction,\n        &MomokaTransactionName::from_str(json_value[\"type\"].as_str().unwrap()).map_err(|_| {\n            TransactionError::new(\n                reference.id.clone(),\n                MomokaVerifierError::InvalidTransactionFormat,\n            )\n        })?,\n    )\n    .map_err(|e| TransactionError::new(reference.id.clone(), e))?;\n\n    // Construct a `TransactionSummary` struct from the transaction data.\n    let transaction_summary = TransactionSummary {\n        id: reference.id.to_owned(),\n        submitter: reference.address.to_owned(),\n        momoka_tx: transaction_type,\n        // For now, we do not have the response from the timestamp proofs.\n        timestamp_proofs_response: None,\n        pointer_transaction_summary: None,\n    };\n\n    // Return the `TransactionSummary` struct.\n    Ok(transaction_summary)\n}\n\n/// Constructs a `TimestampProofsResponse` from a decoded transaction string and a `BundlrTransactionBase64` reference.\n///\n/// # Arguments\n///\n/// * `decoded_transaction` - A string containing the decoded transaction data.\n/// * `reference` - A `BundlrTransactionBase64` reference containing metadata about the transaction.\n///\n/// # Errors\n///\n/// Returns a `MomokaVerifierError` if the decoded transaction data is invalid.\n///\n/// # Returns\n///\n/// Returns a `TimestampProofsResponse` struct containing the transaction's timestamp proofs.\n///\nfn transaction_timestamp_proofs_builder(\n    decoded_transaction: &str,\n    reference: &BundlrTransactionBase64,\n) -> Result<TimestampProofsSummary, TransactionError> {\n    // Parse the decoded transaction data into a `TimestampProofsResponse` struct.\n    let response =\n        serde_json::from_str::<TimestampProofsResponse>(decoded_transaction).map_err(|_| {\n            TransactionError::new(\n                reference.id.clone(),\n                MomokaVerifierError::InvalidTransactionFormat,\n            )\n        })?;\n\n    Ok(TimestampProofsSummary {\n        id: reference.id.to_owned(),\n        response,\n    })\n}\n\n/// Retrieves a single transaction using its ID.\n///\n/// This method retrieves a single transaction specified by its ID. It internally calls the\n/// `get_bulk_transactions_api` method with a slice containing the single transaction ID.\n///\n/// # Arguments\n///\n/// * `tx_id` - A `&MomokaTxId` representing the ID of the transaction to retrieve.\n///\n/// # Returns\n///\n/// A `Result` containing the retrieved `TransactionSummary` if successful, or an error of type\n/// `MomokaVerifierError` if the retrieval fails.\npub async fn get_transaction_api(\n    tx_id: &MomokaTxId,\n) -> Result<TransactionSummary, MomokaVerifierError> {\n    let tx_ids = vec![tx_id.to_owned()];\n    let mut result = get_bulk_transactions_api(&tx_ids).await?;\n    let single_transaction = result\n        .success\n        .pop()\n        .ok_or(MomokaVerifierError::CannotConnectToBundlr)?;\n    Ok(single_transaction)\n}\n\n// Define a constant chunk size\npub const CHUNK_SIZE: usize = 1000;\n\n/// Retrieves bulk transactions and their corresponding timestamp proofs from the API\n///\n/// This function takes a slice of transaction IDs, retrieves the transactions in chunks\n/// from the API, decodes them, retrieves the timestamp proofs for the successful transactions,\n/// and updates the corresponding transaction summaries with the timestamp proofs.\n///\n/// # Arguments\n///\n/// * `tx_ids` - A slice of transaction IDs\n///\n/// # Returns\n///\n/// A result containing the bulk transactions response, which includes the successfully retrieved\n/// and updated transaction summaries, or an error of type `MomokaVerifierError`.\n///\n/// # Example\n///\n/// ```rust\n/// use my_crate::get_bulk_transactions_api;\n///\n/// async fn my_function() {\n///     let tx_ids = vec![\"id1\".to_owned(), \"id2\".to_owned()];\n///     let result = get_bulk_transactions_api(&tx_ids).await;\n///     match result {\n///         Ok(response) => {\n///             // Process the successful response\n///             println!(\"Success: {:?}\", response.success);\n///         }\n///         Err(error) => {\n///             // Handle the error\n///             println!(\"Error: {:?}\", error);\n///         }\n///     }\n/// }\n/// ```\npub async fn get_bulk_transactions_api(\n    tx_ids: &[MomokaTxId],\n) -> Result<BundlrBulkTransactionsResponse<TransactionSummary>, MomokaVerifierError> {\n    let mut combined_response = BundlrBulkTransactionsResponse::<TransactionSummary> {\n        success: vec![],\n        failed: HashMap::new(),\n    };\n\n    let mut futures = vec![];\n    for tx_ids_chunk in tx_ids.chunks(CHUNK_SIZE) {\n        let fut = async move {\n            let transactions_base_64 = get_bulk_transactions_base_64_api(tx_ids_chunk).await?;\n\n            let mut transactions =\n                from_base_64(&transactions_base_64.success, transaction_builder).await?;\n\n            let timestamp_proofs_transaction_ids = transactions\n                .iter()\n                .filter_map(|tx_result| {\n                    tx_result.as_ref().ok().map(|tx_summary| {\n                        tx_summary\n                            .momoka_tx\n                            .get_timestamp_proofs()\n                            .unwrap()\n                            .response\n                            .id\n                            .to_owned()\n                    })\n                })\n                .collect::<Vec<_>>();\n\n            let transactions_timestamp_proofs_base64 =\n                get_bulk_transactions_base_64_api(&timestamp_proofs_transaction_ids)\n                    .await?\n                    .success;\n\n            let transaction_timestamp_proofs = from_base_64(\n                &transactions_timestamp_proofs_base64,\n                transaction_timestamp_proofs_builder,\n            )\n            .await?;\n\n            for (tx_summary, tx_proofs_result) in transactions\n                .iter_mut()\n                .filter_map(|tx_result| tx_result.as_mut().ok())\n                .zip(transaction_timestamp_proofs.into_iter())\n            {\n                if let Ok(tx_proofs) = tx_proofs_result {\n                    let id = &tx_summary.momoka_tx.get_timestamp_proofs()?.response.id;\n\n                    // should not happen but lets panic just incase\n                    assert_eq!(*id, tx_proofs.id);\n                    tx_summary.set_timestamp_proofs_response(tx_proofs.response);\n                }\n            }\n\n            Ok(transactions)\n        };\n        futures.push(fut);\n    }\n\n    let results = futures::future::try_join_all(futures).await?;\n    for result in results.into_iter().flatten() {\n        match result {\n            Ok(tx) => combined_response.success.push(tx),\n            Err(tx_error) => {\n                combined_response.failed.insert(tx_error.id, tx_error.error);\n            }\n        }\n    }\n\n    Ok(combined_response)\n}\n"
  },
  {
    "path": "momoka-rs/src/bundlr/mod.rs",
    "content": "pub mod api;\npub mod verify;\n"
  },
  {
    "path": "momoka-rs/src/bundlr/verify.rs",
    "content": "use crate::types::{\n    transaction::TransactionTimestampProofsValidation, verifier_error::MomokaVerifierError,\n};\nuse bundlr_sdk::{\n    deep_hash::DeepHashChunk, deep_hash_sync::deep_hash_sync, ArweaveSigner, Verifier,\n};\n\nuse data_encoding::BASE64URL_NOPAD;\n\n/// Verifies the timestamp proofs for a transaction.\n///\n/// This function takes a `TransactionTimestampProofsValidation` object, which contains the\n/// timestamp proofs for a transaction, and verifies the signature of the proofs using Arweave's\n/// verification algorithm. If the signature is invalid, this function returns an error.\n///\n/// # Examples\n///\n/// ```\n/// use momoka_verifier::api::verify_timestamp_proofs;\n/// use momoka_verifier::types::transaction::TransactionTimestampProofsValidation;\n/// use momoka_verifier::verifier_error::MomokaVerifierError;\n///\n/// let tx_proofs = TransactionTimestampProofsValidation {\n///     version: \"1\".into(),\n///     id: \"abc123\".into(),\n///     deadline_height: 100,\n///     timestamp: 1620680199,\n///     public_key: \"key\".into(),\n///     signature: \"sig\".into(),\n/// };\n///\n/// let result = verify_timestamp_proofs(&tx_proofs);\n/// assert!(result.is_ok());\n/// ```\npub async fn verify_timestamp_proofs(\n    timestamp_proofs: &TransactionTimestampProofsValidation,\n) -> Result<(), MomokaVerifierError> {\n    let fields = DeepHashChunk::Chunks(vec![\n        DeepHashChunk::Chunk(\"Bundlr\".into()),\n        DeepHashChunk::Chunk(timestamp_proofs.version.clone().into()),\n        DeepHashChunk::Chunk(timestamp_proofs.id.clone().into()),\n        DeepHashChunk::Chunk(timestamp_proofs.deadline_height.to_string().into()),\n        DeepHashChunk::Chunk(timestamp_proofs.timestamp.to_string().into()),\n    ]);\n\n    let pubk = BASE64URL_NOPAD\n        .decode(&timestamp_proofs.public_key.clone().into_bytes())\n        .map_err(|_| MomokaVerifierError::TimestampProofInvalidSignature)?;\n\n    let msg =\n        deep_hash_sync(fields).map_err(|_| MomokaVerifierError::TimestampProofInvalidSignature)?;\n    let sig = BASE64URL_NOPAD\n        .decode(&timestamp_proofs.signature.clone().into_bytes())\n        .map_err(|_| MomokaVerifierError::TimestampProofInvalidSignature)?;\n\n    // Verify the signature using Arweave's verification algorithm\n    ArweaveSigner::verify(pubk.into(), msg, sig.into())\n        .map_err(|_| MomokaVerifierError::TimestampProofInvalidSignature)\n}\n\n#[cfg(test)]\n#[tokio::test]\nasync fn test_verify_timestamp_proofs() {\n    // Prepare the input\n    let timestamp_proofs = TransactionTimestampProofsValidation {\n            id: \"1cgDW9R4aSFXYd2NuVHITPvXQbA13-nUQwS1fhL6R0g\".to_string(),\n            timestamp: 1682525560422,\n            version: \"1.0.0\".to_string(),\n            public_key: \"sq9JbppKLlAKtQwalfX5DagnGMlTirditXk7y4jgoeA7DEM0Z6cVPE5xMQ9kz_T9VppP6BFHtHyZCZODercEVWipzkr36tfQkR5EDGUQyLivdxUzbWgVkzw7D27PJEa4cd1Uy6r18rYLqERgbRvAZph5YJZmpSJk7r3MwnQquuktjvSpfCLFwSxP1w879-ss_JalM9ICzRi38henONio8gll6GV9-omrWwRMZer_15bspCK5txCwpY137nfKwKD5YBAuzxxcj424M7zlSHlsafBwaRwFbf8gHtW03iJER4lR4GxeY0WvnYaB3KDISHQp53a9nlbmiWO5WcHHYsR83OT2eJ0Pl3RWA-_imk_SNwGQTCjmA6tf_UVwL8HzYS2iyuu85b7iYK9ZQoh8nqbNC6qibICE4h9Fe3bN7AgitIe9XzCTOXDfMr4ahjC8kkqJ1z4zNAI6-Leei_Mgd8JtZh2vqFNZhXK0lSadFl_9Oh3AET7tUds2E7s-6zpRPd9oBZu6-kNuHDRJ6TQhZSwJ9ZO5HYsccb_G_1so72aXJymR9ggJgWr4J3bawAYYnqmvmzGklYOlE_5HVnMxf-UxpT7ztdsHbc9QEH6W2bzwxbpjTczEZs3JCCB3c-NewNHsj9PYM3b5tTlTNP9kNAwPZHWpt11t79LuNkNGt9LfOek\".to_string(),\n            signature: \"VwDTklBWgxilmvgwZnal6JvGwF0fKcPx3JqZ5TMo35jKVOEKyCR8czY82x0fYz_rRqeZc96DAJPtMeHaKK-p3Taw-WvEbX9vvDISTjaEQMEYAl1aeAQG-RzcmmB8Ac9a57-OXThDUa88lQPYRrRCu8pIMc1fa-CnBY9CxXJQLv8K1XbZ5L1Hsg97lF64c0wYsxD72svLsc-s9fUmAZ1aB3fpAVYSUgpxK5FPZI1dxFA_TjJSrVEBGUz_ODWho1ZPtGpLlkr81Z10WkaohTLPe-_CBEouLy6fDPCrE3MUUj_-F-OHtzRgK756MQreMxoDEZSXNI22E7CFRiyy_1Rbw4Ax2lu65JeedGnajGcTpTVPlV6UTJRo8kPm6Zo6O6nTqaiZCvnNcLmcOXhNWSSJXVX2zxHWo6kT3ffwKRPuawaNgXFmIDzznfEqg-7uVEByI2UxpD_pF74J44ZxKUurBl8vm6OM7zvyL86VNNTVjafy4Qi6Y45NNqfcbsQpkYfindz0gBWU64NktRE3qUsPce4pL8C1vifL3P7SGF8RLhKedPi52-BNaufRk_vmUlBcNpsvsBSECcCU9SLgY3cSaZekClnPCM2kPQjg5bAIvHr88WSnFwm2niQ8ZZSJPaEEy6qI0QrgXnYDidgbGeUvygeFKG-E2itlF3tBtvR4SlQ\".to_string(),\n            deadline_height: 1170647,\n            block: 1170647,\n            validator_signatures: vec![]\n        };\n\n    // Verify the timestamp proofs\n    let _ = verify_timestamp_proofs(&timestamp_proofs).await.is_ok();\n}\n"
  },
  {
    "path": "momoka-rs/src/cache.rs",
    "content": "use std::collections::HashMap;\nuse std::sync::{Arc, RwLock};\n\nuse crate::types::transaction::MomokaTxId;\nuse crate::types::verifier_error::MomokaVerifierError;\n\npub struct TransactionCacheResult {\n    pub success: bool,\n    pub error: Option<MomokaVerifierError>,\n}\n\nlazy_static::lazy_static! {\n    static ref TRANSACTION_CACHE: RwLock<HashMap<MomokaTxId, Arc<TransactionCacheResult>>> = RwLock::new(HashMap::new());\n    static ref SIGNATURE_CACHE: RwLock<HashMap<String, Arc<()>>> = RwLock::new(HashMap::new());\n}\n\n/// Reads a value from the transaction cache dictionary based on the given key.\n///\n/// # Arguments\n///\n/// * `key` - A momoka tx id slice representing the key to look up in the cache.\n///\n/// # Returns\n///\n/// An `Option` containing a reference to the value if the key is found in the cache, or `None` if the key is not present.\npub fn read_transaction_cache(key: &MomokaTxId) -> Option<Arc<TransactionCacheResult>> {\n    TRANSACTION_CACHE.read().unwrap().get(key).cloned()\n}\n\n/// Sets a value in the transaction cache dictionary based on the given key.\n///\n/// # Arguments\n///\n/// * `key` - A momoka tx id representing the key to set in the cache.\n/// * `value` - The value to associate with the key in the cache.\npub fn set_transaction_cache(key: MomokaTxId, value: TransactionCacheResult) {\n    let cache_value = Arc::new(value);\n    TRANSACTION_CACHE.write().unwrap().insert(key, cache_value);\n}\n\n/// Reads a value from the signature cache dictionary based on the given key.\n///\n/// # Arguments\n///\n/// * `key` - A signature slice representing the key to look up in the cache.\n///\n/// # Returns\n///\n/// An `Option` containing a reference to the value if the key is found in the cache, or `None` if the key is not present.\npub fn read_signature_cache(key: &str) -> Option<Arc<()>> {\n    SIGNATURE_CACHE.read().unwrap().get(key).cloned()\n}\n\n/// Sets a value in the signature cache dictionary based on the given key.\n///\n/// # Arguments\n///\n/// * `key` - A signature representing the key to set in the cache.\n/// * `value` - The value to associate with the key in the cache.\npub fn set_signature_cache(key: String) {\n    let cache_value = Arc::new(());\n    SIGNATURE_CACHE.write().unwrap().insert(key, cache_value);\n}\n"
  },
  {
    "path": "momoka-rs/src/contracts/lens_hub.rs",
    "content": "use std::{fs, sync::Arc};\n\nuse ethers::{\n    abi::Abi,\n    prelude::{abigen, Contract, Multicall},\n    providers::{Http, Provider, RetryClient},\n    types::{Address, BlockNumber, U256},\n};\n\nuse crate::types::{profile_id::ProfileId, verifier_error::MomokaVerifierError};\n\nabigen!(\n    ILensHub,\n    \"./src/abi/lens_hub_contract_abi.json\",\n    event_derives(serde::Deserialize, serde::Serialize)\n);\n\n/// Returns a new instance of `ILensHub`, representing the Lens Protocol Hub contract\n/// deployed on the Polygon (Matic) mainnet.\n/// # Arguments\n///\n/// * `provider` - The ethers provider\n///\n/// # Example\n///\n/// ```\n/// let provider =  Provider::<Http>::try_from(node_url).unwrap();\n/// let contract = lens_hub_contract(&provider);\n/// ```\npub fn lens_hub_contract(\n    lens_hub: Address,\n    // provider: &RetryClient<Http>,\n    provider: &Provider<RetryClient<Http>>,\n) -> ILensHub<&Provider<RetryClient<Http>>> {\n    // Create a new client from the provider\n    let client = Arc::new(provider);\n\n    // Create a new instance of the ILensHub contract using the address and client\n    let contract: ILensHub<&Provider<RetryClient<Http>>> = ILensHub::new(lens_hub, client);\n\n    contract\n}\n\n/// Represents the details of a lens profile.\npub struct LensProfileDetails {\n    /// The signature nonce of the lens profile.\n    pub sig_nonce: U256,\n    /// The current publication ID of the lens profile.\n    pub current_publication_id: U256,\n    /// The address of the dispatcher contract.\n    pub dispatcher_address: Address,\n    /// The owner of the address.\n    pub owner_of_address: Address,\n}\n\n/// Gets the details of a Lens profile, including the current publication ID and the owner of the address.\n///\n/// # Arguments\n///\n/// * `profile_id` - The ID of the Lens profile in hexadecimal format.\n/// * `signed_by_address` - The address of the signer.\n/// * `provider` - The ethers provider\n///\n/// # Errors\n///\n/// This function can return an error if there is an issue with the ABI or if the contract call fails.\n///\n/// # Examples\n///\n/// ```\n/// use ethers::prelude::*;\n/// use std::str::FromStr;\n/// use std::sync::Arc;\n///\n/// let profile_id = \"0x01\";\n/// let signed_by_address = Address::from_str(\"0x1234...\").unwrap();\n///\n/// let details = get_profile_details(&profile_id, &signed_by_address).await.unwrap();\n/// assert_eq!(details.sig_nonce, U256::from(42));\n/// assert_eq!(details.current_publication_id, U256::from(1234));\n/// ```\npub async fn get_profile_details(\n    lens_hub: Address,\n    profile_id: &ProfileId,\n    signed_by_address: Address,\n    block_number: u64,\n    provider: &Provider<RetryClient<Http>>,\n) -> Result<LensProfileDetails, MomokaVerifierError> {\n    let abi: Abi = serde_json::from_str(\n        &fs::read_to_string(\"./src/abi/lens_hub_contract_abi.json\")\n            .map_err(|_| MomokaVerifierError::SimulationNodeCouldNotRun)?,\n    )\n    .map_err(|_| MomokaVerifierError::SimulationNodeCouldNotRun)?;\n\n    let provider = Arc::new(&(provider));\n\n    let contract = Contract::new(lens_hub, abi, provider.clone());\n\n    let profile_id = <&ProfileId as Into<U256>>::into(profile_id);\n\n    let sig_nonce_call = contract\n        .method::<_, U256>(\"sigNonces\", (signed_by_address,))\n        .map_err(|_| MomokaVerifierError::SimulationNodeCouldNotRun)?;\n    let get_pub_count = contract\n        .method::<_, U256>(\"getPubCount\", profile_id)\n        .map_err(|_| MomokaVerifierError::SimulationNodeCouldNotRun)?;\n    let get_dispatcher = contract\n        .method::<_, Address>(\"getDispatcher\", profile_id)\n        .map_err(|_| MomokaVerifierError::SimulationNodeCouldNotRun)?;\n\n    let owner_of = contract\n        .method::<_, Address>(\"ownerOf\", profile_id)\n        .map_err(|_| MomokaVerifierError::SimulationNodeCouldNotRun)?;\n\n    let mut multicall = Multicall::new(provider.clone(), None)\n        .await\n        .map_err(|_| MomokaVerifierError::SimulationNodeCouldNotRun)?\n        .block(BlockNumber::from(block_number));\n\n    multicall\n        .add_call(sig_nonce_call, false)\n        .add_call(get_pub_count, false)\n        .add_call(get_dispatcher, false)\n        .add_call(owner_of, false);\n\n    let return_data: (U256, U256, Address, Address) = multicall\n        .call()\n        .await\n        .map_err(|_| MomokaVerifierError::SimulationNodeCouldNotRun)?;\n\n    Ok(LensProfileDetails {\n        sig_nonce: return_data.0,\n        current_publication_id: return_data.1,\n        dispatcher_address: return_data.2,\n        owner_of_address: return_data.3,\n    })\n}\n"
  },
  {
    "path": "momoka-rs/src/contracts/mod.rs",
    "content": "pub mod lens_hub;\n"
  },
  {
    "path": "momoka-rs/src/environment.rs",
    "content": "use std::str::FromStr;\n\nuse ethers::types::Address;\n\n/// Represents different deployment environments.\n#[derive(Debug, Clone)]\npub enum Deployment {\n    Production,\n    Staging,\n    Local,\n}\n\nimpl FromStr for Deployment {\n    type Err = ();\n\n    /// Parses a string into a `Deployment` enum variant.\n    ///\n    /// # Arguments\n    ///\n    /// * `s` - A string slice representing the deployment value.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` containing the parsed `Deployment` variant if successful, or an error if parsing fails.\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s.to_ascii_lowercase().as_str() {\n            \"production\" => Ok(Deployment::Production),\n            \"staging\" => Ok(Deployment::Staging),\n            \"local\" => Ok(Deployment::Local),\n            _ => Err(()),\n        }\n    }\n}\n\n/// Contains information about the environment configuration.\n#[derive(Debug)]\npub struct EnvironmentInfo {\n    /// The environment value.\n    pub environment: Environment,\n    /// The URL of the node.\n    pub node_url: String,\n    /// The deployment value.\n    pub deployment: Deployment,\n}\n\n/// Represents different network environments.\n#[derive(Debug, Clone)]\npub enum Environment {\n    Polygon,\n    Mumbai,\n    Amoy,\n    Sandbox,\n}\n\nimpl FromStr for Environment {\n    type Err = ();\n\n    /// Parses a string into an `Environment` enum variant.\n    ///\n    /// # Arguments\n    ///\n    /// * `s` - A string slice representing the environment value.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` containing the parsed `Environment` variant if successful, or an error if parsing fails.\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s.to_lowercase().as_str() {\n            \"polygon\" => Ok(Environment::Polygon),\n            \"mumbai\" => Ok(Environment::Mumbai),\n            \"amoy\" => Ok(Environment::Amoy),\n            \"sandbox\" => Ok(Environment::Sandbox),\n            _ => Err(()),\n        }\n    }\n}\n\n/// Maps an Ethereum environment to its corresponding chain ID.\n///\n/// # Arguments\n///\n/// * `environment` - The Ethereum environment to map to a chain ID.\n///\n/// # Returns\n///\n/// The chain ID corresponding to the provided Ethereum environment.\n///\n/// # Errors\n///\n/// An error is returned if the provided environment is invalid.\n#[allow(dead_code, unreachable_patterns)]\npub fn environment_to_chain_id(environment: Environment) -> Result<u32, &'static str> {\n    match environment {\n        Environment::Polygon => Ok(137),\n        Environment::Mumbai | Environment::Sandbox => Ok(80001),\n        Environment::Amoy => Ok(80002),\n        _ => Err(\"Invalid environment\"),\n    }\n}\n\n/// Maps an Ethereum environment to its corresponding Lens Hub contract address.\n///\n/// # Arguments\n///\n/// * `environment` - The Ethereum environment to map to a Lens Hub contract address.\n///\n/// # Returns\n///\n/// The Lens Hub contract address corresponding to the provided Ethereum environment.\n///\n/// # Errors\n///\n/// An error is returned if the provided environment is invalid.\n#[allow(unreachable_patterns)]\npub fn environment_to_lens_hub_contract(\n    environment: &Environment,\n) -> Result<Address, &'static str> {\n    match environment {\n        Environment::Polygon => {\n            Ok(Address::from_str(\"0xDb46d1Dc155634FbC732f92E853b10B288AD5a1d\").unwrap())\n        }\n        Environment::Mumbai => {\n            Ok(Address::from_str(\"0x60Ae865ee4C725cd04353b5AAb364553f56ceF82\").unwrap())\n        }\n        Environment::Amoy => {\n            Ok(Address::from_str(\"0xA2574D9DdB6A325Ad2Be838Bd854228B80215148\").unwrap())\n        }\n        Environment::Sandbox => {\n            Ok(Address::from_str(\"0x7582177F9E536aB0b6c721e11f383C326F2Ad1D5\").unwrap())\n        }\n        _ => Err(\"Invalid environment\"),\n    }\n}\n"
  },
  {
    "path": "momoka-rs/src/evm.rs",
    "content": "use std::{str::FromStr, time::Duration};\n\nuse ethers::{\n    providers::{Http, HttpRateLimitRetryPolicy, Provider, RetryClient, RetryClientBuilder},\n    utils::hex,\n};\nuse serde::{Deserialize, Serialize};\n\nuse crate::{\n    environment::{Deployment, Environment},\n    types::verifier_error::MomokaVerifierError,\n};\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct SigRequest {\n    pub v: u8,\n    pub r: [u8; 32],\n    pub s: [u8; 32],\n    pub deadline: u64,\n}\n\n/// Parses the signature string and constructs a `SigRequest` object.\n///\n/// This function takes a signature string in hexadecimal format and decodes it into its\n/// corresponding components: `v`, `r`, `s`, and `deadline`. The resulting components are\n/// used to create a `SigRequest` object that represents the signature.\n///\n/// # Arguments\n///\n/// * `signature` - The signature string in hexadecimal format.\n/// * `deadline` - The deadline value associated with the signature.\n///\n/// # Errors\n///\n/// This function returns a `Result` which can contain a `MomokaVerifierError` if the\n/// signature fails to decode from hexadecimal format.\n///\n/// # Examples\n///\n/// ```\n/// use crate::MomokaVerifierError;\n///\n/// let signature = \"0x1234567890abcdef\";\n/// let deadline = 1234567890;\n///\n/// match parse_signature(signature, deadline) {\n///     Ok(sig_request) => println!(\"{:?}\", sig_request),\n///     Err(err) => eprintln!(\"Failed to parse signature: {:?}\", err),\n/// }\n/// ```\npub fn parse_signature(signature: &str, deadline: u64) -> Result<SigRequest, MomokaVerifierError> {\n    let bytes = hex::decode(&signature[2..]).map_err(|_| MomokaVerifierError::SimulationFailed)?;\n    let v = bytes[64];\n    let mut r_bytes = [0u8; 32];\n    r_bytes.copy_from_slice(&bytes[..32]);\n    let mut s_bytes = [0u8; 32];\n    s_bytes.copy_from_slice(&bytes[32..64]);\n\n    Ok(SigRequest {\n        v,\n        r: r_bytes,\n        s: s_bytes,\n        deadline,\n    })\n}\n\n/// Represents the provider context, including the environment, node provider, and deployment details.\n#[derive(Debug)]\npub struct ProviderContext {\n    /// The environment configuration.\n    pub environment: Environment,\n    /// The node provider with retry capabilities.\n    pub node: Provider<RetryClient<Http>>,\n    /// The deployment details.\n    pub deployment: Deployment,\n}\n\n/// Creates an EVM provider using the provided node URL.\n///\n/// # Arguments\n///\n/// * `node_url` - The URL of the Ethereum node to connect to.\n///\n/// # Returns\n///\n/// A provider instance with retry capabilities for interacting with the EVM.\npub fn evm_provider(node_url: &str) -> Provider<RetryClient<Http>> {\n    Provider::new(\n        RetryClientBuilder::default()\n            .rate_limit_retries(10)\n            .timeout_retries(10)\n            .initial_backoff(Duration::from_millis(500))\n            .build(\n                Http::from_str(node_url).unwrap(),\n                Box::<HttpRateLimitRetryPolicy>::default(),\n            ),\n    )\n}\n"
  },
  {
    "path": "momoka-rs/src/http.rs",
    "content": "use reqwest::Client;\nuse serde::de::DeserializeOwned;\nuse serde::Serialize;\nuse std::thread::sleep;\nuse std::time::Duration;\n\nconst MAX_RETRIES: i32 = 5;\n\n/// Sends a POST request to the specified URL with a JSON-encoded body, and returns the response as a deserialized object.\n///\n/// # Arguments\n///\n/// * `url` - The URL to which the request will be sent.\n/// * `body` - The body of the request, which will be JSON-encoded and sent as the request payload.\n///\n/// # Returns\n///\n/// The deserialized response object, if the request was successful.\n///\n/// # Errors\n///\n/// This function will return an error if the request fails for any reason, or if the response cannot be deserialized into the specified type.\n///\n/// # Example\n///\n/// ```\n/// use momoka_verifier::calls::post_with_timeout;\n/// use momoka_verifier::types::verifier_error::MomokaVerifierError;\n///\n/// #[derive(serde::Deserialize)]\n/// struct ExampleResponse {\n///     message: String,\n///     value: i32,\n/// }\n///\n/// async fn example_post_request() -> Result<ExampleResponse, MomokaVerifierError> {\n///     let body = serde_json::json!({\n///         \"some_key\": \"some_value\",\n///         \"another_key\": 42,\n///     });\n///     let response = post_with_timeout::<ExampleResponse, _>(\"http://example.com/api/endpoint\", &body).await?;\n///     Ok(response)\n/// }\n/// ```\npub async fn post_with_timeout<TResponse, TBody>(\n    url: &str,\n    body: &TBody,\n) -> Result<TResponse, reqwest::Error>\nwhere\n    TBody: Serialize,\n    TResponse: DeserializeOwned,\n{\n    let mut retries = 0;\n\n    loop {\n        match post_request(url, body).await {\n            Ok(response) => return Ok(response),\n            Err(err) => {\n                if retries >= MAX_RETRIES {\n                    return Err(err);\n                }\n                // sleep for 100ms and go again\n                sleep(Duration::from_millis(100));\n                retries += 1;\n            }\n        }\n    }\n}\n\n/// Performs a POST request with a timeout and JSON body serialization.\n///\n/// # Arguments\n///\n/// * `url` - The URL to send the POST request to.\n/// * `body` - The body of the request, to be serialized as JSON.\n///\n/// # Returns\n///\n/// A `Result` containing the deserialized response if the request is successful, or an `Error` if an error occurs.\nasync fn post_request<TResponse, TBody>(\n    url: &str,\n    body: &TBody,\n) -> Result<TResponse, reqwest::Error>\nwhere\n    TBody: serde::Serialize,\n    TResponse: serde::de::DeserializeOwned,\n{\n    let client = Client::new();\n\n    let response = client\n        .post(url)\n        .timeout(Duration::from_millis(10000))\n        .header(\"Content-Type\", \"application/json\")\n        .json(body)\n        .send()\n        .await?;\n\n    response.json().await\n}\n"
  },
  {
    "path": "momoka-rs/src/logger.rs",
    "content": "use crate::utils::get_current_utc_string;\n\n/// A logger for printing log messages in different colors.\npub struct Logger;\n\n#[allow(dead_code)]\nimpl Logger {\n    fn print_colored_message(&self, color_code: &str, content: &str) {\n        println!(\n            \"{}LENS VERIFICATION NODE - {} - {}\\x1b[0m\",\n            color_code,\n            get_current_utc_string(),\n            content\n        );\n    }\n\n    /// Prints an error message with the specified content in red.\n    ///\n    /// # Arguments\n    ///\n    /// * `content` - The content of the error message.\n    pub fn error(&self, content: &str) {\n        self.print_colored_message(\"\\x1b[31m\", content); // Red\n    }\n\n    /// Prints a warning message with the specified content in yellow.\n    ///\n    /// # Arguments\n    ///\n    /// * `content` - The content of the warning message.\n    pub fn warning(&self, content: &str) {\n        self.print_colored_message(\"\\x1b[33m\", content); // Yellow\n    }\n\n    /// Prints an informational message with the specified content in blue.\n    ///\n    /// # Arguments\n    ///\n    /// * `content` - The content of the informational message.\n    pub fn info(&self, content: &str) {\n        self.print_colored_message(\"\\x1b[36m\", content); // Blue\n    }\n\n    /// Prints a success message with the specified content in green.\n    ///\n    /// # Arguments\n    ///\n    /// * `content` - The content of the success message.\n    pub fn success(&self, content: &str) {\n        self.print_colored_message(\"\\x1b[38;2;0;128;0m\", content); // Green\n    }\n}\n"
  },
  {
    "path": "momoka-rs/src/main.rs",
    "content": "mod bundlr;\nmod cache;\nmod contracts;\nmod environment;\nmod evm;\nmod http;\nmod logger;\nmod submitter;\nmod types;\nmod utils;\nmod verifier;\n\nuse clap::{arg, Parser};\nuse environment::{Deployment, Environment};\nuse evm::ProviderContext;\nuse logger::Logger;\nuse core::panic;\nuse std::collections::HashSet;\nuse std::process::exit;\nuse std::{str::FromStr, thread::sleep, time::Duration};\n\nuse types::transaction::MomokaTxId;\nuse verifier::proof::check_proof;\n\nuse crate::{\n    bundlr::api::{get_bulk_transactions_ids_api, get_last_transaction_api},\n    verifier::proof::check_proofs,\n};\n\n/// Creates a `ProviderContext` based on the provided parameters.\n///\n/// # Arguments\n///\n/// * `node_url` - The URL of the Ethereum node.\n/// * `environment` - The environment name (optional). Defaults to \"POLYGON\" if not provided.\n/// * `deployment` - The deployment name (optional). Defaults to \"PRODUCTION\" if not provided.\n///\n/// # Panics\n///\n/// This function panics if the provided environment or deployment values are invalid.\n///\n/// # Returns\n///\n/// A `ProviderContext` containing the configured environment, node provider, and deployment.\npub fn create_provider_context(\n    node_url: String,\n    environment: Option<String>,\n    deployment: Option<String>,\n) -> ProviderContext {\n    let environment = environment.unwrap_or(\"POLYGON\".to_string());\n\n    let etherem_network = Environment::from_str(&environment).unwrap_or_else(|_| {\n        Logger.error(\"Invalid value for ENVIRONMENT\");\n        exit(1);\n    });\n\n    let deployment = deployment.unwrap_or(\"PRODUCTION\".to_string());\n\n    let deployment = Deployment::from_str(&deployment).unwrap_or_else(|_| {\n        Logger.error(\"Invalid value for DEPLOYMENT\");\n        exit(1);\n    });\n\n    ProviderContext {\n        environment: etherem_network,\n        node: evm::evm_provider(&node_url),\n        deployment,\n    }\n}\n\n/// Command line arguments for the momoka-rs program.\n#[derive(Parser)]\n#[command(author, version, about, long_about = None)]\nstruct Cli {\n    /// The URL of the node.\n    #[arg(short = 'n', value_name = \"NODE\")]\n    node: Option<String>,\n\n    /// The environment (e.g., \"MUMBAI\" or \"POLYGON\").\n    #[arg(short = 'e', value_name = \"ENVIRONMENT\")]\n    environment: Option<String>,\n\n    /// The deployment (e.g., \"PRODUCTION\").\n    #[arg(short = 'd', value_name = \"DEPLOYMENT\")]\n    deployment: Option<String>,\n\n    /// The transaction ID to check proof for.\n    #[arg(short = 't', value_name = \"TX_ID\")]\n    tx_id: Option<MomokaTxId>,\n\n    /// Flag indicating whether to perform a resync.\n    #[arg(short = 'r', value_name = \"RESYNC\")]\n    resync: bool,\n}\n\n#[tokio::main]\nasync fn main() {\n    Logger.info(\"                                                                                                                       \n        MMMMMMMM               MMMMMMMM     OOOOOOOOO     MMMMMMMM               MMMMMMMM     OOOOOOOOO     KKKKKKKKK    KKKKKKK               AAA               \n        M:::::::M             M:::::::M   OO:::::::::OO   M:::::::M             M:::::::M   OO:::::::::OO   K:::::::K    K:::::K              A:::A              \n        M::::::::M           M::::::::M OO:::::::::::::OO M::::::::M           M::::::::M OO:::::::::::::OO K:::::::K    K:::::K             A:::::A             \n        M:::::::::M         M:::::::::MO:::::::OOO:::::::OM:::::::::M         M:::::::::MO:::::::OOO:::::::OK:::::::K   K::::::K            A:::::::A            \n        M::::::::::M       M::::::::::MO::::::O   O::::::OM::::::::::M       M::::::::::MO::::::O   O::::::OKK::::::K  K:::::KKK           A:::::::::A           \n        M:::::::::::M     M:::::::::::MO:::::O     O:::::OM:::::::::::M     M:::::::::::MO:::::O     O:::::O  K:::::K K:::::K             A:::::A:::::A          \n        M:::::::M::::M   M::::M:::::::MO:::::O     O:::::OM:::::::M::::M   M::::M:::::::MO:::::O     O:::::O  K::::::K:::::K             A:::::A A:::::A         \n        M::::::M M::::M M::::M M::::::MO:::::O     O:::::OM::::::M M::::M M::::M M::::::MO:::::O     O:::::O  K:::::::::::K             A:::::A   A:::::A        \n        M::::::M  M::::M::::M  M::::::MO:::::O     O:::::OM::::::M  M::::M::::M  M::::::MO:::::O     O:::::O  K:::::::::::K            A:::::A     A:::::A       \n        M::::::M   M:::::::M   M::::::MO:::::O     O:::::OM::::::M   M:::::::M   M::::::MO:::::O     O:::::O  K::::::K:::::K          A:::::AAAAAAAAA:::::A      \n        M::::::M    M:::::M    M::::::MO:::::O     O:::::OM::::::M    M:::::M    M::::::MO:::::O     O:::::O  K:::::K K:::::K        A:::::::::::::::::::::A     \n        M::::::M     MMMMM     M::::::MO::::::O   O::::::OM::::::M     MMMMM     M::::::MO::::::O   O::::::OKK::::::K  K:::::KKK    A:::::AAAAAAAAAAAAA:::::A    \n        M::::::M               M::::::MO:::::::OOO:::::::OM::::::M               M::::::MO:::::::OOO:::::::OK:::::::K   K::::::K   A:::::A             A:::::A   \n        M::::::M               M::::::M OO:::::::::::::OO M::::::M               M::::::M OO:::::::::::::OO K:::::::K    K:::::K  A:::::A               A:::::A  \n        M::::::M               M::::::M   OO:::::::::OO   M::::::M               M::::::M   OO:::::::::OO   K:::::::K    K:::::K A:::::A                 A:::::A \n        MMMMMMMM               MMMMMMMM     OOOOOOOOO     MMMMMMMM               MMMMMMMM     OOOOOOOOO     KKKKKKKKK    KKKKKKKAAAAAAA                   AAAAAAA\n   \");\n\n    Logger.info(\"Starting momoka verifier up...\");\n\n    let args = Cli::parse();\n\n    // Check if a node URL is provided\n    let node_url = match args.node {\n        Some(url) => url,\n        None => {\n            Logger\n                .warning(\"YOUR USING A SHARED NODE, BUSY TIMES THINGS COULD FAIL DUE TO LOW RATE LIMITS AND THAT IT IS A SHARED NODE.\");\n            if args.environment.as_ref().is_none() {\n                \"https://polygon-mainnet.g.alchemy.com/v2/yzw8av5xB7xEAJLyoSLRYqKIaxbJ-mby\"\n                    .to_string()\n            } else {\n                let node = match args.environment.as_ref().unwrap().to_string().as_str() {\n                    \"MUMBAI\" => {\n                        \"https://polygon-mumbai.g.alchemy.com/v2/aqPaIMBhpTSK9WImCS6ELYuRflnIPRAv\"\n                            .to_string()\n                    }\n                    \"POLYGON\" => {\n                        \"https://polygon-mainnet.g.alchemy.com/v2/yzw8av5xB7xEAJLyoSLRYqKIaxbJ-mby\"\n                            .to_string()\n                    }\n                    \"AMOY\" => {\n                        panic!(\"No shared node setup for amoy please use your own\")\n                    }\n                    _ => {\n                        Logger.error(\"Invalid value for ENVIRONMENT\");\n                        exit(1);\n                    }\n                };\n\n                node\n            }\n        }\n    };\n\n    let provider_context = create_provider_context(node_url, args.environment, args.deployment);\n\n    // Check if a single transaction ID is provided\n    if let Some(tx_id) = args.tx_id {\n        Logger.info(\"Checking proof for a single transaction...\");\n        if let Err(err) = check_proof(&tx_id, &provider_context).await {\n            Logger.error(&format!(\"Proof check failed: {}\", err));\n            exit(1);\n        }\n        exit(0);\n    }\n\n    let mut end_cursor = None;\n    if args.resync {\n        Logger.info(\"Resyncing momoka verifier, this will start from the first ever transaction and validate them all...\");\n    } else {\n        let last_transaction =\n            get_last_transaction_api(&provider_context.environment, &provider_context.deployment)\n                .await\n                .unwrap();\n        end_cursor = Some(last_transaction.cursor);\n    }\n\n    let mut init_complete = false;\n\n    loop {\n        match get_bulk_transactions_ids_api(\n            &provider_context.environment,\n            &provider_context.deployment,\n            &end_cursor,\n            // Fetch 1,000 at a time! We can extend this if desired.\n            1,\n        )\n        .await\n        {\n            Ok(transactions) => {\n                if transactions.is_none() {\n                    if !init_complete {\n                        Logger.info(\"Waiting for new momoka transactions...\");\n                    }\n                    sleep(Duration::from_millis(100));\n                    init_complete = true;\n                    continue;\n                }\n\n                let transactions = transactions.unwrap();\n                end_cursor = transactions.next;\n\n                let result = check_proofs(\n                    // remove any duplicates\n                    &transactions\n                        .tx_ids\n                        .into_iter()\n                        .collect::<HashSet<String>>()\n                        .into_iter()\n                        .collect(),\n                    &provider_context,\n                )\n                .await;\n\n                if let Err(err) = result {\n                    Logger.error(&format!(\"Proof check failed: {}\", err));\n                    exit(1);\n                }\n            }\n            Err(err) => {\n                let message = err.to_string();\n                println!(\"Momoka error: {}\", message);\n                sleep(Duration::from_millis(100));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "momoka-rs/src/submitter/mod.rs",
    "content": "pub mod state;\n"
  },
  {
    "path": "momoka-rs/src/submitter/state.rs",
    "content": "use std::str::FromStr;\n\nuse ethers::types::Address;\n\nuse crate::environment::{Deployment, Environment};\n\n/// Returns the list of authorized submitters for a given environment and deployment.\n///\n/// This method will return a list of authorized submitters for a given environment and deployment.\n///\n/// # Arguments\n///\n/// * `environment` - An `Environment` value representing the target environment.\n/// * `deployment` - A `Deployment` value representing the target deployment.\n///\n/// # Examples\n///\n/// ```\n/// use momoka_sdk::shared::{get_submitters, Environment, Deployment};\n///\n/// let environment = Environment::MUMBAI;\n/// let deployment = Deployment::STAGING;\n///\n/// let submitters = get_submitters(&environment, &deployment);\n/// assert_eq!(submitters.len(), 1);\n/// ```\npub fn get_submitters(environment: &Environment, deployment: &Deployment) -> Vec<Address> {\n    match deployment {\n        Deployment::Production => match environment {\n            Environment::Polygon => {\n                vec![Address::from_str(\"0xBe29464B9784a0d8956f29630d8bc4D7B5737435\").unwrap()]\n            }\n            Environment::Mumbai => {\n                vec![Address::from_str(\"0xEE3E8f53df70C3A3eeDA2076CDCa17c451aa8F96\").unwrap()]\n            }\n            Environment::Amoy => {\n                vec![Address::from_str(\"0x085be9a079aB75608fB794f2D288A375856e3f60\").unwrap()]\n            }\n            Environment::Sandbox => panic!(\"Not Supported\"),\n        },\n        Deployment::Staging => match environment {\n            Environment::Polygon => panic!(\"Not Supported\"),\n            Environment::Mumbai => {\n                vec![Address::from_str(\"0x122938FE0d1fC6e00EF1b814cD7e44677e99b4f7\").unwrap()]\n            }\n            Environment::Amoy => {\n                vec![Address::from_str(\"0xC1b3BF1D611f1148F1799E90f7342860499Ba9D9\").unwrap()]\n            }\n            Environment::Sandbox => panic!(\"Not Supported\"),\n        },\n        Deployment::Local => match environment {\n            Environment::Polygon => panic!(\"Not Supported\"),\n            Environment::Mumbai => {\n                vec![Address::from_str(\"0x8Fc176aA6FC843D3422f0C1832f1b9E17be00C1c\").unwrap()]\n            }\n            Environment::Amoy => {\n                vec![Address::from_str(\"0xcD7739d0b2ceFAb809FEF4e839a55b2627B60205\").unwrap()]\n            }\n            Environment::Sandbox => panic!(\"Not Supported\"),\n        },\n    }\n}\n\n/// Checks if a given address is an authorized submitter.\n///\n/// This method will check if a given address is an authorized submitter for a given environment and deployment.\n///\n/// # Arguments\n///\n/// * `environment` - An `Environment` value representing the target environment.\n/// * `address` - A `&str` value representing the address to check.\n/// * `deployment` - A `Deployment` value representing the target deployment.\n///\n/// # Examples\n///\n/// ```\n/// use momoka_sdk::shared::{is_valid_submitter, Environment, Deployment};\n///\n/// let environment = Environment::MUMBAI;\n/// let deployment = Deployment::STAGING;\n///\n/// let is_valid = is_valid_submitter(&environment, \"0x122938FE0d1fC6e00EF1b814cD7e44677e99b4f7\", &deployment);\n/// assert!(is_valid);\n/// ```\npub fn is_valid_submitter(\n    environment: &Environment,\n    address: &Address,\n    deployment: &Deployment,\n) -> bool {\n    get_submitters(environment, deployment).contains(address)\n}\n"
  },
  {
    "path": "momoka-rs/src/types/chain_proofs.rs",
    "content": "use ethers::types::H256;\nuse serde::{Deserialize, Serialize};\n\nuse super::{eip721::TypedData, transaction::TransactionPointer};\n\n/// Represents a collection of cryptographic proofs related to a chain publication,\n/// where the proofs are verified and validated by the chain. This proof structure is\n/// specific to the Lens Network protocol and depends on the format of typed data and\n/// the blockchain where the publication was recorded.\n///\n/// `TTypedData` is the type of the typed data that is part of this publication,\n/// and `TPointer` is the type of the transaction pointer, which may be `Option<TransactionPointer>`\n/// or a similar type depending on how it is being used.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct ChainProofs<TTypedData, TPointer>\nwhere\n    TTypedData: TypedData,\n    TPointer: Into<Option<TransactionPointer>>,\n{\n    /// The current chain publication\n    pub this_publication: ChainPublication<TTypedData>,\n\n    /// The transaction pointer\n    pub pointer: TPointer,\n}\n\n/// Represents a publication on the chain that has been signed by the delegate,\n/// and can be verified and validated by the chain.\n///\n/// `TTypedData` is the type of the typed data that is part of this publication.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct ChainPublication<TTypedData>\nwhere\n    TTypedData: TypedData,\n{\n    /// The signature for the publication\n    pub signature: String,\n\n    /// Indicates whether the publication was signed by the delegate or not\n    pub signed_by_delegate: bool,\n\n    /// The deadline for the signature\n    pub signature_deadline: u64,\n\n    /// The typed data\n    pub typed_data: TTypedData,\n\n    /// The block hash\n    pub block_hash: H256,\n\n    /// The block number\n    pub block_number: u64,\n\n    /// The block timestamp\n    pub block_timestamp: u64,\n}\n"
  },
  {
    "path": "momoka-rs/src/types/eip721.rs",
    "content": "use ethers::types::{\n    transaction::eip712::{EIP712Domain, Eip712DomainType},\n    Address, U256,\n};\nuse serde::{Deserialize, Serialize};\n\nuse super::{hex::Hex, profile_id::ProfileId, publication_id::PublicationId};\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct TypedDataDomain {\n    pub name: String,\n\n    pub version: String,\n\n    pub chain_id: u32,\n\n    pub verifying_contract: Address,\n}\n\nimpl TypedDataDomain {\n    pub fn to_ethers_type(&self) -> EIP712Domain {\n        EIP712Domain {\n            name: Some(self.name.clone()),\n            version: Some(self.version.clone()),\n            chain_id: Some(U256::from(self.chain_id)),\n            salt: None,\n            verifying_contract: Some(self.verifying_contract),\n        }\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct EIP712TypedData<TTypes, TValue> {\n    pub types: TTypes,\n\n    pub domain: TypedDataDomain,\n\n    pub value: TValue,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct EIP712TypedDataValueBase {\n    pub nonce: u32,\n\n    pub deadline: u32,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct CreatePostEIP712TypedDataValue {\n    pub profile_id: ProfileId,\n\n    #[serde(rename = \"contentURI\")]\n    pub content_uri: String,\n\n    pub collect_module: Address,\n\n    pub collect_module_init_data: Hex,\n\n    pub reference_module: Address,\n\n    pub reference_module_init_data: Hex,\n\n    pub nonce: u64,\n\n    pub deadline: u64,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct CreatePostEIP712Types {\n    #[serde(rename = \"PostWithSig\")]\n    pub post_with_sig: Vec<Eip712DomainType>,\n}\n\npub type CreatePostEIP712TypedData =\n    EIP712TypedData<CreatePostEIP712Types, CreatePostEIP712TypedDataValue>;\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct CreateCommentEIP712TypedDataValue {\n    pub profile_id: ProfileId,\n\n    pub profile_id_pointed: ProfileId,\n\n    pub pub_id_pointed: PublicationId,\n\n    #[serde(rename = \"contentURI\")]\n    pub content_uri: String,\n\n    pub reference_module: Address,\n\n    pub collect_module: Address,\n\n    pub collect_module_init_data: Hex,\n\n    pub reference_module_init_data: Hex,\n\n    pub reference_module_data: Hex,\n\n    pub nonce: u64,\n\n    pub deadline: u64,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct CreateCommentEIP712Types {\n    #[serde(rename = \"CommentWithSig\")]\n    pub comment_with_sig: Vec<Eip712DomainType>,\n}\n\npub type CreateCommentEIP712TypedData =\n    EIP712TypedData<CreateCommentEIP712Types, CreateCommentEIP712TypedDataValue>;\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct CreateMirrorEIP712TypedDataValue {\n    pub profile_id: ProfileId,\n\n    pub profile_id_pointed: ProfileId,\n\n    pub pub_id_pointed: PublicationId,\n\n    pub reference_module_data: Hex,\n\n    pub reference_module: Address,\n\n    pub reference_module_init_data: Hex,\n\n    pub nonce: u64,\n\n    pub deadline: u64,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct CreateMirrorEIP712Types {\n    #[serde(rename = \"MirrorWithSig\")]\n    pub mirror_with_sig: Vec<Eip712DomainType>,\n}\n\npub type CreateMirrorEIP712TypedData =\n    EIP712TypedData<CreateMirrorEIP712Types, CreateMirrorEIP712TypedDataValue>;\n\npub trait TypedData {}\nimpl<T> TypedData for Box<T> where T: TypedData + ?Sized {}\nimpl TypedData for CreatePostEIP712TypedData {}\nimpl TypedData for CreateCommentEIP712TypedData {}\nimpl TypedData for CreateMirrorEIP712TypedData {}\n"
  },
  {
    "path": "momoka-rs/src/types/evm_event.rs",
    "content": "use ethers::types::Address;\nuse serde::{Deserialize, Serialize};\n\nuse super::{hex::Hex, profile_id::ProfileId, publication_id::PublicationId};\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct PostCreatedEventEmittedResponse {\n    pub profile_id: ProfileId,\n\n    pub pub_id: PublicationId,\n\n    #[serde(rename = \"contentURI\")]\n    pub content_uri: String,\n\n    pub collect_module: Address,\n\n    pub collect_module_return_data: Hex,\n\n    pub reference_module: Address,\n\n    pub reference_module_return_data: Hex,\n\n    pub timestamp: u64,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct CommentCreatedEventEmittedResponse {\n    pub profile_id: ProfileId,\n\n    pub pub_id: PublicationId,\n\n    #[serde(rename = \"contentURI\")]\n    pub content_uri: String,\n\n    pub profile_id_pointed: ProfileId,\n\n    pub pub_id_pointed: PublicationId,\n\n    pub reference_module_data: Hex,\n\n    pub collect_module: Address,\n\n    pub collect_module_return_data: Hex,\n\n    pub reference_module: Address,\n\n    pub reference_module_return_data: Hex,\n\n    pub timestamp: u64,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct MirrorCreatedEventEmittedResponse {\n    pub profile_id: ProfileId,\n\n    pub pub_id: PublicationId,\n\n    pub profile_id_pointed: ProfileId,\n\n    pub pub_id_pointed: PublicationId,\n\n    pub reference_module_data: Hex,\n\n    pub reference_module: Address,\n\n    pub reference_module_return_data: Hex,\n\n    pub timestamp: u64,\n}\n\npub trait EvmEvent {\n    fn get_timestamp(&self) -> u64;\n}\n\nimpl<T> EvmEvent for Box<T>\nwhere\n    T: EvmEvent + ?Sized,\n{\n    fn get_timestamp(&self) -> u64 {\n        (**self).get_timestamp()\n    }\n}\n\nimpl EvmEvent for PostCreatedEventEmittedResponse {\n    fn get_timestamp(&self) -> u64 {\n        self.timestamp\n    }\n}\n\nimpl EvmEvent for CommentCreatedEventEmittedResponse {\n    fn get_timestamp(&self) -> u64 {\n        self.timestamp\n    }\n}\n\nimpl EvmEvent for MirrorCreatedEventEmittedResponse {\n    fn get_timestamp(&self) -> u64 {\n        self.timestamp\n    }\n}\n"
  },
  {
    "path": "momoka-rs/src/types/hex.rs",
    "content": "use ethers::types::U256;\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\nuse std::fmt;\n\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct Hex(Vec<u8>);\n\n#[allow(dead_code)]\nimpl Hex {\n    pub fn new(bytes: Vec<u8>) -> Self {\n        Hex(bytes)\n    }\n\n    pub fn empty() -> Self {\n        Hex(Vec::new())\n    }\n\n    pub fn as_bytes(&self) -> &[u8] {\n        &self.0\n    }\n\n    pub fn is_empty(&self) -> bool {\n        self.0.is_empty()\n    }\n\n    pub fn as_str(&self) -> String {\n        format!(\"0x{}\", hex::encode(&self.0))\n    }\n}\n\nimpl<'de> Deserialize<'de> for Hex {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        struct HexVisitor;\n\n        impl<'de> serde::de::Visitor<'de> for HexVisitor {\n            type Value = Hex;\n\n            fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {\n                formatter.write_str(\"a hexadecimal string starting with '0x'\")\n            }\n\n            fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>\n            where\n                E: serde::de::Error,\n            {\n                if value == \"0x\" {\n                    Ok(Hex::empty())\n                } else {\n                    let hex_string = value.trim_start_matches(\"0x\");\n                    let bytes = hex::decode(hex_string).map_err(serde::de::Error::custom)?;\n                    Ok(Hex(bytes))\n                }\n            }\n        }\n\n        deserializer.deserialize_str(HexVisitor)\n    }\n}\n\nimpl Serialize for Hex {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        let hex_string = format!(\"0x{}\", hex::encode(&self.0));\n        serializer.serialize_str(&hex_string)\n    }\n}\n\nimpl From<Hex> for Vec<u8> {\n    fn from(hex: Hex) -> Self {\n        hex.0\n    }\n}\n\nimpl From<Hex> for U256 {\n    fn from(hex: Hex) -> Self {\n        U256::from_str_radix(&hex.as_str(), 16).unwrap()\n    }\n}\n\nimpl<'a> From<&'a Hex> for U256 {\n    fn from(hex: &'a Hex) -> Self {\n        U256::from_str_radix(&hex.as_str(), 16).expect(\"Invalid hex string\")\n    }\n}\n\nimpl From<Hex> for ethers::types::Bytes {\n    fn from(bytes: Hex) -> Self {\n        ethers::types::Bytes(bytes.0.into())\n    }\n}\n"
  },
  {
    "path": "momoka-rs/src/types/mod.rs",
    "content": "pub mod chain_proofs;\npub mod eip721;\npub mod evm_event;\npub mod hex;\npub mod profile_id;\npub mod publication_id;\npub mod transaction;\npub mod verifier_error;\n"
  },
  {
    "path": "momoka-rs/src/types/profile_id.rs",
    "content": "use ethers::types::U256;\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\nuse std::fmt;\n\n/// Represents a profile ID as a wrapper around U256.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct ProfileId(U256);\n\nimpl ProfileId {\n    /// Creates a new ProfileId instance.\n    pub fn new(value: U256) -> Self {\n        ProfileId(value)\n    }\n\n    /// Returns the inner U256 value.\n    pub fn into_inner(self) -> U256 {\n        self.0\n    }\n\n    /// Returns the profile ID as a formatted hex string.\n    pub fn as_str(&self) -> String {\n        let mut hex_string = format!(\"{:x}\", self.0);\n        if hex_string.len() % 2 != 0 {\n            hex_string.insert(0, '0');\n        }\n        format!(\"0x{}\", hex_string)\n    }\n}\n\nimpl From<U256> for ProfileId {\n    fn from(value: U256) -> Self {\n        ProfileId::new(value)\n    }\n}\n\nimpl Serialize for ProfileId {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        serializer.serialize_str(&self.as_str())\n    }\n}\n\nimpl<'de> Deserialize<'de> for ProfileId {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let hex_string = String::deserialize(deserializer)?;\n        let profile_id = U256::from_str_radix(hex_string.trim_start_matches(\"0x\"), 16)\n            .map_err(serde::de::Error::custom)?;\n        Ok(ProfileId::new(profile_id))\n    }\n}\n\nimpl fmt::Display for ProfileId {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.as_str())\n    }\n}\n\nimpl From<ProfileId> for U256 {\n    fn from(profile_id: ProfileId) -> Self {\n        U256::from_str_radix(&profile_id.as_str(), 16).unwrap()\n    }\n}\n\nimpl<'a> From<&'a ProfileId> for U256 {\n    fn from(profile_id: &'a ProfileId) -> Self {\n        U256::from_str_radix(&profile_id.as_str(), 16).expect(\"Invalid profile id\")\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[derive(Debug)]\n    struct TestData {\n        u256: U256,\n        profile_id_str: String,\n    }\n\n    fn get_test_data() -> Vec<TestData> {\n        vec![\n            TestData {\n                u256: U256::from(1),\n                profile_id_str: \"0x01\".to_owned(),\n            },\n            TestData {\n                u256: U256::from_dec_str(\"10\").unwrap(),\n                profile_id_str: \"0x0a\".to_owned(),\n            },\n            TestData {\n                u256: U256::MAX,\n                profile_id_str:\n                    \"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff\".to_owned(),\n            },\n        ]\n    }\n\n    #[test]\n    fn test_new_profile_id() {\n        let test_data = get_test_data();\n        for data in test_data {\n            let profile_id = ProfileId::new(data.u256);\n            assert_eq!(profile_id.into_inner(), data.u256);\n        }\n    }\n\n    #[test]\n    fn test_serialize_deserialize_profile_id() {\n        let test_data = get_test_data();\n        for data in test_data {\n            let profile_id = ProfileId::new(data.u256);\n\n            // Serialize the ProfileId and deserialize it back into a new ProfileId\n            let serialized = serde_json::to_string(&profile_id).unwrap();\n            let deserialized: ProfileId = serde_json::from_str(&serialized).unwrap();\n\n            assert_eq!(deserialized, profile_id);\n        }\n    }\n\n    #[test]\n    fn test_display() {\n        let test_data = get_test_data();\n        for data in test_data {\n            let profile_id = ProfileId::new(data.u256);\n            assert_eq!(format!(\"{}\", profile_id), data.profile_id_str);\n        }\n    }\n\n    #[test]\n    fn test_from_profile_id_to_u256() {\n        let test_data = get_test_data();\n        for data in test_data {\n            let profile_id = ProfileId::new(data.u256);\n            let u256: U256 = profile_id.into();\n\n            assert_eq!(u256, data.u256);\n        }\n    }\n\n    #[test]\n    fn test_from_ref_profile_id_to_u256() {\n        let test_data = get_test_data();\n        for data in test_data {\n            let profile_id = ProfileId::new(data.u256);\n            let u256: U256 = (&profile_id).into();\n\n            assert_eq!(u256, data.u256);\n        }\n    }\n}\n"
  },
  {
    "path": "momoka-rs/src/types/publication_id.rs",
    "content": "use ethers::types::U256;\nuse serde::{Deserialize, Deserializer, Serialize, Serializer};\nuse std::fmt;\n\n/// Represents a publication ID as a wrapper around U256.\n#[derive(Debug, Clone, PartialEq, Eq)]\npub struct PublicationId(U256);\n\nimpl PublicationId {\n    /// Creates a new PublicationId instance.\n    pub fn new(value: U256) -> Self {\n        PublicationId(value)\n    }\n\n    /// Returns the inner U256 value.\n    pub fn into_inner(self) -> U256 {\n        self.0\n    }\n\n    /// Returns the publication ID as a formatted hex string.\n    pub fn as_str(&self) -> String {\n        let mut hex_string = format!(\"{:x}\", self.0);\n        if hex_string.len() % 2 != 0 {\n            hex_string.insert(0, '0');\n        }\n        format!(\"0x{}\", hex_string)\n    }\n}\n\nimpl From<U256> for PublicationId {\n    fn from(value: U256) -> Self {\n        PublicationId::new(value)\n    }\n}\n\nimpl Serialize for PublicationId {\n    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>\n    where\n        S: Serializer,\n    {\n        serializer.serialize_str(&self.as_str())\n    }\n}\n\nimpl<'de> Deserialize<'de> for PublicationId {\n    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>\n    where\n        D: Deserializer<'de>,\n    {\n        let hex_string = String::deserialize(deserializer)?;\n        let publication_id = U256::from_str_radix(hex_string.trim_start_matches(\"0x\"), 16)\n            .map_err(serde::de::Error::custom)?;\n        Ok(PublicationId::new(publication_id))\n    }\n}\n\nimpl fmt::Display for PublicationId {\n    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {\n        write!(f, \"{}\", self.as_str())\n    }\n}\n\nimpl From<PublicationId> for U256 {\n    fn from(publication_id: PublicationId) -> Self {\n        U256::from_str_radix(&publication_id.as_str(), 16).unwrap()\n    }\n}\n\nimpl<'a> From<&'a PublicationId> for U256 {\n    fn from(publication_id: &'a PublicationId) -> Self {\n        U256::from_str_radix(&publication_id.as_str(), 16).expect(\"Invalid hex string\")\n    }\n}\n\n#[cfg(test)]\nmod tests {\n    use super::*;\n\n    #[test]\n    fn test_publication_id_new() {\n        let u256 = U256::from(42u64);\n        let publication_id = PublicationId::new(u256);\n\n        // Assert that the PublicationId constructor returns the expected value\n        assert_eq!(publication_id, PublicationId(U256::from(42u64)));\n    }\n\n    #[test]\n    fn test_publication_id_into_inner() {\n        let u256 = U256::from(42u64);\n        let publication_id = PublicationId::new(u256);\n\n        // Assert that the into_inner method returns the expected value\n        assert_eq!(publication_id.into_inner(), U256::from(42u64));\n    }\n\n    #[test]\n    fn test_publication_id_as_str() {\n        let u256 = U256::from(42u64);\n        let publication_id = PublicationId::new(u256);\n\n        // Assert that the as_str method returns the expected value\n        assert_eq!(publication_id.as_str(), \"0x2a\");\n    }\n\n    #[test]\n    fn test_publication_id_from_u256() {\n        let u256 = U256::from(42u64);\n        let publication_id = PublicationId::from(u256);\n\n        // Assert that the From<U256> implementation returns the expected value\n        assert_eq!(publication_id, PublicationId(U256::from(42u64)));\n    }\n\n    #[test]\n    fn test_publication_id_serde() {\n        let publiation_id = PublicationId::new(U256::from(1));\n\n        let serialized = serde_json::to_string(&publiation_id).unwrap();\n        let deserialized: PublicationId = serde_json::from_str(&serialized).unwrap();\n\n        assert_eq!(deserialized, publiation_id);\n    }\n\n    #[test]\n    fn test_publication_id_fmt() {\n        let u256 = U256::from(42u64);\n        let publication_id = PublicationId::new(u256);\n\n        // Assert that the Display implementation returns the expected value\n        assert_eq!(format!(\"{}\", publication_id), \"0x2a\");\n    }\n}\n"
  },
  {
    "path": "momoka-rs/src/types/transaction.rs",
    "content": "use std::str::FromStr;\n\nuse crate::evm::ProviderContext;\nuse crate::verifier::transactions::comment::verifier_comment;\nuse crate::verifier::transactions::mirror::verifier_mirror;\nuse crate::verifier::transactions::post::verifier_post;\n\nuse super::eip721::{\n    CreateCommentEIP712TypedDataValue, CreateCommentEIP712Types, CreateMirrorEIP712TypedDataValue,\n    CreateMirrorEIP712Types, CreatePostEIP712TypedDataValue, EIP712TypedData, TypedData,\n};\nuse super::evm_event::EvmEvent;\nuse super::profile_id::ProfileId;\nuse super::publication_id::PublicationId;\nuse super::verifier_error::MomokaVerifierError;\nuse super::{\n    chain_proofs::ChainProofs,\n    eip721::{\n        CreateCommentEIP712TypedData, CreateMirrorEIP712TypedData, CreatePostEIP712TypedData,\n    },\n    evm_event::{\n        CommentCreatedEventEmittedResponse, MirrorCreatedEventEmittedResponse,\n        PostCreatedEventEmittedResponse,\n    },\n};\nuse ethers::types::Address;\nuse json::JsonValue;\nuse serde::{Deserialize, Serialize};\nuse uuid::Uuid;\n\npub type MomokaTxId = String;\n\n/// An enum representing the type of action associated with a transaction.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"SCREAMING_SNAKE_CASE\")]\n#[allow(clippy::enum_variant_names)]\npub enum TransactionAction {\n    PostCreated,\n    CommentCreated,\n    MirrorCreated,\n}\n\n/// An enum representing the type of provider associated with a transaction.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"SCREAMING_SNAKE_CASE\")]\npub enum TransactionProvider {\n    Bundlr,\n}\n\n/// An enum representing the type of pointer associated with a transaction.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"SCREAMING_SNAKE_CASE\")]\npub enum TransactionPointerType {\n    OnEvmChain,\n    OnDa,\n}\n\n/// A struct representing the signature of a validator for transaction timestamp proofs.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct TransactionTimestampProofsValidatorSignature {\n    pub address: String,\n    pub signature: String,\n}\n\n/// A struct representing the validation of transaction timestamp proofs.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct TransactionTimestampProofsValidation {\n    /// The ID of the transaction.\n    pub id: MomokaTxId,\n\n    /// The UNIX (MS precision) timestamp of when the node received the Tx. Only optional if the upload receives a `201` error in response to a duplicate transaction upload.\n    pub timestamp: u64,\n\n    /// Response version.\n    pub version: String,\n\n    /// The public key of the validating node.\n    #[serde(rename = \"public\")]\n    pub public_key: String,\n\n    /// The signature of this receipt.\n    pub signature: String,\n\n    /// The deadline height.\n    pub deadline_height: u64,\n\n    /// The maximum expected Arweave block height for transaction inclusion.\n    pub block: u32,\n\n    /// The validator signatures.\n    pub validator_signatures: Vec<TransactionTimestampProofsValidatorSignature>,\n}\n\n/// A struct representing the summary of a timestamp proof.\npub struct TimestampProofsSummary {\n    /// The ID of the transaction.\n    pub id: MomokaTxId,\n\n    /// The response to the timestamp proof validation.\n    pub response: TimestampProofsResponse,\n}\n\n/// A struct representing the response to a timestamp proof validation.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct TimestampProofsResponse {\n    /// The action type.\n    #[serde(rename = \"type\")]\n    pub action_type: TransactionAction,\n\n    /// The data availability ID.\n    pub data_availability_id: Uuid,\n}\n\n/// A struct representing a pointer to a transaction.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct TransactionPointer {\n    /// The location of the pointer.\n    // #[serde(deserialize_with = \"parse_and_replace\")]\n    pub location: String,\n\n    /// The type of pointer.\n    #[serde(rename = \"type\")]\n    pub pointer_type: TransactionPointerType,\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct BasePublication<TEvent, TTypedData, TPointer>\nwhere\n    TEvent: EvmEvent,\n    TTypedData: TypedData,\n    TPointer: Into<Option<TransactionPointer>>,\n{\n    /// The signature of the publication.\n    pub signature: String,\n\n    /// The ID of the data availability layer used for this publication.\n    pub data_availability_id: Uuid,\n\n    /// The type of the transaction that generated this publication.\n    #[serde(rename = \"type\")]\n    pub publication_type: TransactionAction,\n\n    /// Timestamp proofs of the transaction that generated this publication.\n    pub timestamp_proofs: TransactionTimestampProofs,\n\n    /// Chain proofs of the transaction that generated this publication.\n    pub chain_proofs: ChainProofs<TTypedData, TPointer>,\n\n    /// The ID of the publication.\n    pub publication_id: String,\n\n    /// The event that generated this publication.\n    pub event: TEvent,\n}\n\n/// A `BasePublication` representing a post created on the platform.\npub type PostCreatedPublication = BasePublication<\n    PostCreatedEventEmittedResponse,\n    CreatePostEIP712TypedData,\n    Option<TransactionPointer>,\n>;\n\nimpl PostCreatedPublication {\n    pub fn typed_data_value(&self) -> &CreatePostEIP712TypedDataValue {\n        &self.chain_proofs.this_publication.typed_data.value\n    }\n\n    pub fn profile_id(&self) -> &ProfileId {\n        &self.typed_data_value().profile_id\n    }\n}\n\n/// A `BasePublication` representing a comment created on the platform.\npub type CommentCreatedPublication = BasePublication<\n    CommentCreatedEventEmittedResponse,\n    CreateCommentEIP712TypedData,\n    Option<TransactionPointer>,\n>;\n\nimpl CommentCreatedPublication {\n    pub fn typed_data(\n        &self,\n    ) -> &EIP712TypedData<CreateCommentEIP712Types, CreateCommentEIP712TypedDataValue> {\n        &self.chain_proofs.this_publication.typed_data\n    }\n\n    pub fn profile_id(&self) -> &ProfileId {\n        &self.typed_data().value.profile_id\n    }\n\n    pub fn signature(&self) -> &String {\n        &self.chain_proofs.this_publication.signature\n    }\n\n    pub fn nonce(&self) -> &u64 {\n        &self.typed_data().value.nonce\n    }\n}\n\n/// A `BasePublication` representing a mirror created on the platform.\npub type MirrorCreatedPublication = BasePublication<\n    MirrorCreatedEventEmittedResponse,\n    CreateMirrorEIP712TypedData,\n    Option<TransactionPointer>,\n>;\n\nimpl MirrorCreatedPublication {\n    pub fn typed_data(\n        &self,\n    ) -> &EIP712TypedData<CreateMirrorEIP712Types, CreateMirrorEIP712TypedDataValue> {\n        &self.chain_proofs.this_publication.typed_data\n    }\n\n    pub fn profile_id(&self) -> &ProfileId {\n        &self.typed_data().value.profile_id\n    }\n\n    pub fn signature(&self) -> &String {\n        &self.chain_proofs.this_publication.signature\n    }\n\n    pub fn nonce(&self) -> &u64 {\n        &self.typed_data().value.nonce\n    }\n}\n\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[allow(clippy::enum_variant_names)]\n/// An enum representing a Momoka transaction.\npub enum MomokaTransaction {\n    PostCreated(PostCreatedPublication),\n    CommentCreated(CommentCreatedPublication),\n    MirrorCreated(MirrorCreatedPublication),\n}\n\n#[derive(Debug, Clone, PartialEq, Eq)]\n#[allow(clippy::enum_variant_names)]\n/// An enum representing a Momoka transaction name.\npub enum MomokaTransactionName {\n    PostCreated,\n    CommentCreated,\n    MirrorCreated,\n}\n\nimpl FromStr for MomokaTransactionName {\n    type Err = ();\n\n    fn from_str(s: &str) -> Result<Self, Self::Err> {\n        match s {\n            \"POST_CREATED\" => Ok(MomokaTransactionName::PostCreated),\n            \"COMMENT_CREATED\" => Ok(MomokaTransactionName::CommentCreated),\n            \"MIRROR_CREATED\" => Ok(MomokaTransactionName::MirrorCreated),\n            _ => Err(()),\n        }\n    }\n}\n\n#[allow(unreachable_patterns)]\nimpl MomokaTransaction {\n    /// Converts a JSON-encoded transaction of a given type to the corresponding `MomokaTransaction`.\n    ///\n    /// # Arguments\n    ///\n    /// * `json` - A `&str` containing the JSON-encoded transaction data.\n    /// * `transaction_type` - A reference to a `MomokaTransactionName` indicating the type of transaction to parse.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` containing a `MomokaTransaction` object if the transaction was parsed successfully, or a `MomokaVerifierError` if there was an error parsing the transaction or the transaction type is not recognized.\n    pub fn from_json(\n        json: &str,\n        transaction_type: &MomokaTransactionName,\n    ) -> Result<Self, MomokaVerifierError> {\n        match transaction_type {\n            MomokaTransactionName::PostCreated => {\n                serde_json::from_str::<PostCreatedPublication>(json)\n                    .map(MomokaTransaction::PostCreated)\n                    .map_err(|_| MomokaVerifierError::InvalidTransactionFormat)\n            }\n            MomokaTransactionName::CommentCreated => {\n                serde_json::from_str::<CommentCreatedPublication>(json)\n                    .map(MomokaTransaction::CommentCreated)\n                    .map_err(|_| MomokaVerifierError::InvalidTransactionFormat)\n            }\n            MomokaTransactionName::MirrorCreated => {\n                serde_json::from_str::<MirrorCreatedPublication>(json)\n                    .map(MomokaTransaction::MirrorCreated)\n                    .map_err(|_| MomokaVerifierError::InvalidTransactionFormat)\n            }\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Returns a reference to the timestamp proofs associated with the transaction.\n    ///\n    /// # Returns\n    ///\n    /// A reference to the `TransactionTimestampProofs` object containing the timestamp proofs.\n    pub fn get_timestamp_proofs(&self) -> Result<&TransactionTimestampProofs, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::PostCreated(publication) => Ok(&publication.timestamp_proofs),\n            MomokaTransaction::CommentCreated(publication) => Ok(&publication.timestamp_proofs),\n            MomokaTransaction::MirrorCreated(publication) => Ok(&publication.timestamp_proofs),\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Determines if the event timestamp of a `MomokaTransaction` matches the block timestamp\n    /// associated with it in the transaction's chain proofs.\n    ///\n    /// Returns `Ok(true)` if the timestamps match, otherwise `Ok(false)`.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error of type `MomokaVerifierError::InvalidTransactionType` if the `MomokaTransaction`\n    /// variant is not supported.\n    pub fn is_valid_event_timestamp(&self) -> Result<bool, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(e) => {\n                Ok(e.event.timestamp == e.chain_proofs.this_publication.block_timestamp)\n            }\n            MomokaTransaction::MirrorCreated(e) => {\n                Ok(e.event.timestamp == e.chain_proofs.this_publication.block_timestamp)\n            }\n            MomokaTransaction::PostCreated(e) => {\n                Ok(e.event.timestamp == e.chain_proofs.this_publication.block_timestamp)\n            }\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Determines whether the typed data deadline timestamp in this transaction\n    /// matches the block timestamp.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` containing a `bool` indicating whether the typed data deadline\n    /// timestamp matches the block timestamp, or an `Err` if the transaction\n    /// type is invalid.\n    pub fn is_valid_typed_data_deadline_timestamp(&self) -> Result<bool, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(e) => {\n                Ok(e.chain_proofs.this_publication.typed_data.value.deadline\n                    == e.chain_proofs.this_publication.block_timestamp)\n            }\n            MomokaTransaction::MirrorCreated(e) => {\n                Ok(e.chain_proofs.this_publication.typed_data.value.deadline\n                    == e.chain_proofs.this_publication.block_timestamp)\n            }\n            MomokaTransaction::PostCreated(e) => {\n                Ok(e.chain_proofs.this_publication.typed_data.value.deadline\n                    == e.chain_proofs.this_publication.block_timestamp)\n            }\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Verifies the integrity of a `PostCreatedPublication` using the Ethereum blockchain.\n    ///\n    /// # Arguments\n    ///\n    /// * `publication` - A `PostCreatedPublication` to be verified.\n    /// * `provider_context` - The provider context\n    ///\n    /// # Returns\n    ///\n    /// A `Result<(), MomokaVerifierError>` indicating whether the verification succeeded or failed.\n    pub async fn validate_transaction(\n        &self,\n        provider_context: &ProviderContext,\n    ) -> Result<(), MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(e) => verifier_comment(e, provider_context).await,\n            MomokaTransaction::MirrorCreated(e) => verifier_mirror(e, provider_context).await,\n            MomokaTransaction::PostCreated(e) => verifier_post(e, provider_context).await,\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Retrieves the block number associated with the transaction.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` containing a reference to the block number, or a `MomokaVerifierError` if the transaction type is invalid.\n    pub fn block_number(&self) -> Result<&u64, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(e) => {\n                Ok(&e.chain_proofs.this_publication.block_number)\n            }\n            MomokaTransaction::MirrorCreated(e) => {\n                Ok(&e.chain_proofs.this_publication.block_number)\n            }\n            MomokaTransaction::PostCreated(e) => Ok(&e.chain_proofs.this_publication.block_number),\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Returns a reference to the transaction signature.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error of `MomokaVerifierError::InvalidTransactionType` if called on an invalid transaction type.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use momoka_rs::{MomokaTransaction, MomokaVerifierError};\n    ///\n    /// let tx = MomokaTransaction::PostCreated(...);\n    /// let signature = tx.signature()?;\n    /// println!(\"Transaction signature: {}\", signature);\n    /// ```\n    pub fn signature(&self) -> Result<&str, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(e) => Ok(&e.signature),\n            MomokaTransaction::MirrorCreated(e) => Ok(&e.signature),\n            MomokaTransaction::PostCreated(e) => Ok(&e.signature),\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Returns a reference to the timestamp in the third-party timestamp proofs of the transaction.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error of type `MomokaVerifierError::InvalidTransactionType` if the transaction\n    /// is not of type `CommentCreated`, `MirrorCreated`, or `PostCreated`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use momoka_rs::{MomokaTransaction, MomokaVerifierError};\n    ///\n    /// let tx = MomokaTransaction::CommentCreated(comment);\n    /// let timestamp = tx.third_party_proofs_timestamp()?;\n    ///\n    /// assert_eq!(*timestamp, 1621380354);\n    /// # Ok::<(), MomokaVerifierError>(())\n    /// ```\n    pub fn third_party_proofs_timestamp(&self) -> Result<&u64, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(e) => Ok(&e.timestamp_proofs.response.timestamp),\n            MomokaTransaction::MirrorCreated(e) => Ok(&e.timestamp_proofs.response.timestamp),\n            MomokaTransaction::PostCreated(e) => Ok(&e.timestamp_proofs.response.timestamp),\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Returns a reference to the `TransactionPointer` contained in this transaction's\n    /// `ChainPublicationProofs`, or `None` if the transaction type is `PostCreated`.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use momoka_rs::{MomokaTransaction, TransactionPointer};\n    ///\n    /// let pointer = Some(TransactionPointer {\n    ///     txid: \"0x1234567890abcdef\".to_string(),\n    ///     block_hash: \"0x0987654321fedcba\".to_string(),\n    ///     block_number: 123456,\n    /// });\n    ///\n    /// let tx = MomokaTransaction::CommentCreated(MyCommentPublication {\n    ///     // ...\n    ///     chain_proofs: ChainPublicationProofs {\n    ///         this_publication: ChainPublication {\n    ///             // ...\n    ///             pointer,\n    ///         },\n    ///         // ...\n    ///     },\n    ///     // ...\n    /// });\n    ///\n    /// assert_eq!(tx.pointer().unwrap(), &pointer);\n    /// ```\n    pub fn pointer(&self) -> Result<&Option<TransactionPointer>, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(e) => Ok(&e.chain_proofs.pointer),\n            MomokaTransaction::MirrorCreated(e) => Ok(&e.chain_proofs.pointer),\n            MomokaTransaction::PostCreated(_) => Ok(&None),\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Formats a publication ID by combining the given `profile_id`, `pub_id`, and `data_availability_id`.\n    ///\n    /// The resulting ID is in the format `profile_id-pub_id-DA-{short_data_availability_id}`, where\n    /// `short_data_availability_id` is the first substring before the first '-' character in `data_availability_id`.\n    ///\n    /// # Arguments\n    ///\n    /// * `profile_id`: A `String` representing the profile ID.\n    /// * `pub_id`: A `String` representing the publication ID.\n    /// * `data_availability_id`: A `String` representing the data availability ID.\n    ///\n    /// # Returns\n    ///\n    /// A `String` representing the formatted publication ID.\n    fn format_publication_id(\n        &self,\n        profile_id: &ProfileId,\n        pub_id: &PublicationId,\n        data_availability_id: &Uuid,\n    ) -> Result<String, MomokaVerifierError> {\n        let end_id = data_availability_id\n            .to_string()\n            .split('-')\n            .next()\n            .ok_or(MomokaVerifierError::GeneratedPublicationIdMismatch)?\n            .to_string();\n\n        Ok(format!(\"{}-{}-DA-{}\", profile_id, pub_id, end_id))\n    }\n\n    /// Generates a publication ID based on the transaction event's profile ID, publication ID,\n    /// and data availability ID.\n    ///\n    /// This function formats the publication ID using the `format_publication_id` method and returns\n    /// a reference to the generated ID string.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error of type `MomokaVerifierError::InvalidTransactionType` if the transaction\n    /// is not of type `CommentCreated`, `MirrorCreated`, or `PostCreated`, or if an error occurs\n    /// while formatting the publication ID.\n    ///\n    /// # Arguments\n    ///\n    /// * `self`: A reference to the `MomokaTransaction` instance.\n    ///\n    /// # Returns\n    ///\n    /// A `Result` containing a reference to the generated publication ID string, or an error if\n    /// the transaction type is invalid or an error occurs during for\n    fn generate_publication_id(&self) -> Result<String, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(e) => Ok(self.format_publication_id(\n                &e.event.profile_id,\n                &e.event.pub_id,\n                &e.data_availability_id,\n            )?),\n            MomokaTransaction::MirrorCreated(e) => Ok(self.format_publication_id(\n                &e.event.profile_id,\n                &e.event.pub_id,\n                &e.data_availability_id,\n            )?),\n            MomokaTransaction::PostCreated(e) => Ok(self.format_publication_id(\n                &e.event.profile_id,\n                &e.event.pub_id,\n                &e.data_availability_id,\n            )?),\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Checks whether the generated publication ID matches the publication ID\n    /// contained within the transaction.\n    ///\n    /// # Returns\n    ///\n    /// - `Ok(true)` if the generated publication ID matches the transaction's\n    ///   publication ID.\n    /// - `Ok(false)` if the generated publication ID does not match the\n    ///   transaction's publication ID.\n    /// - `Err` if the transaction type is invalid or if there is an error\n    ///   generating the publication ID.\n    pub fn valid_publication_id(&self) -> Result<bool, MomokaVerifierError> {\n        let generated_publication_id = self.generate_publication_id()?;\n        match self {\n            MomokaTransaction::CommentCreated(e) => {\n                Ok(generated_publication_id == e.publication_id)\n            }\n            MomokaTransaction::MirrorCreated(e) => Ok(generated_publication_id == e.publication_id),\n            MomokaTransaction::PostCreated(e) => Ok(generated_publication_id == e.publication_id),\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Returns the address of the verifying contract for the transaction.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error of type `MomokaVerifierError::InvalidTransactionType` if the transaction\n    /// type is not supported.\n    ///\n    /// # Returns\n    ///\n    /// Returns a reference to the address of the verifying contract.\n    ///\n    pub fn verifying_contract(&self) -> Result<&Address, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(e) => Ok(&e\n                .chain_proofs\n                .this_publication\n                .typed_data\n                .domain\n                .verifying_contract),\n            MomokaTransaction::MirrorCreated(e) => Ok(&e\n                .chain_proofs\n                .this_publication\n                .typed_data\n                .domain\n                .verifying_contract),\n            MomokaTransaction::PostCreated(e) => Ok(&e\n                .chain_proofs\n                .this_publication\n                .typed_data\n                .domain\n                .verifying_contract),\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Returns the transaction type associated with the `MomokaTransaction`.\n    ///\n    /// # Returns\n    ///\n    /// - `Ok(&TransactionAction)`: The transaction type.\n    /// - `Err(MomokaVerifierError)`: If the transaction type is invalid.\n    pub fn transaction_type(&self) -> Result<&TransactionAction, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(t) => Ok(&t.publication_type),\n            MomokaTransaction::MirrorCreated(t) => Ok(&t.publication_type),\n            MomokaTransaction::PostCreated(t) => Ok(&t.publication_type),\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Returns the data availability ID associated with the `MomokaTransaction`.\n    ///\n    /// # Returns\n    ///\n    /// - `Ok(&Uuid)`: The data availability ID.\n    /// - `Err(MomokaVerifierError)`: If the transaction type is invalid.\n    pub fn data_availability_id(&self) -> Result<&Uuid, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(t) => Ok(&t.data_availability_id),\n            MomokaTransaction::MirrorCreated(t) => Ok(&t.data_availability_id),\n            MomokaTransaction::PostCreated(t) => Ok(&t.data_availability_id),\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    /// Returns the collect module address specified in the typed data of the transaction.\n    ///\n    /// # Errors\n    ///\n    /// Returns an error if the transaction type is not supported.\n    ///\n    /// # Examples\n    ///\n    /// ```\n    /// use ethers::types::Address;\n    /// use crate::MomokaVerifierError;\n    ///\n    /// let tx = MomokaTransaction::PostCreated(PostCreatedPublication {\n    ///     event: PostCreatedEventEmittedResponse {\n    ///         profile_id: \"profile_id\".to_string(),\n    ///         pub_id: \"pub_id\".to_string(),\n    ///         title: \"title\".to_string(),\n    ///         author: \"author\".to_string(),\n    ///         timestamp: 123456789,\n    ///         data_type: \"data_type\".to_string(),\n    ///     },\n    ///     chain_proofs: PublicationChainData {\n    ///         this_publication: PublicationProofData {\n    ///             typed_data: EIP712TypedData {\n    ///                 domain: EIP712TypedDataDomain {\n    ///                     name: \"name\".to_string(),\n    ///                     version: \"version\".to_string(),\n    ///                     chain_id: 1.into(),\n    ///                     verifying_contract: Address::zero(),\n    ///                 },\n    ///                 types: EIP712Types::default(),\n    ///                 primary_type: \"primary_type\".to_string(),\n    ///                 message: CreatePostEIP712TypedDataValue {\n    ///                     author: \"author\".to_string(),\n    ///                     title: \"title\".to_string(),\n    ///                     data_type: \"data_type\".to_string(),\n    ///                     profile_id: \"profile_id\".to_string(),\n    ///                     pub_id: \"pub_id\".to_string(),\n    ///                     deadline: 123456789,\n    ///                 },\n    ///             },\n    ///             block_timestamp: 123456789,\n    ///             block_number: 1.into(),\n    ///         },\n    ///         pointer: None,\n    ///     },\n    ///     timestamp_proofs: TimestampResponse {\n    ///         publisher: \"publisher\".to_string(),\n    ///         data_availability_id: \"data_availability_id\".to_string(),\n    ///         response: TimestampProof {\n    ///             timestamp: 123456789,\n    ///             signature: \"signature\".to_string(),\n    ///         },\n    ///     },\n    ///     data_availability_id: \"data_availability_id\".to_string(),\n    /// });\n    ///\n    /// let result = tx.typed_data_collect_module();\n    ///\n    /// assert_eq!(result.unwrap(), &Address::zero());\n    /// ```\n    pub fn typed_data_collect_module(&self) -> Result<Option<&Address>, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(e) => Ok(Some(\n                &e.chain_proofs\n                    .this_publication\n                    .typed_data\n                    .value\n                    .collect_module,\n            )),\n            MomokaTransaction::MirrorCreated(_) => Ok(None),\n            MomokaTransaction::PostCreated(e) => Ok(Some(\n                &e.chain_proofs\n                    .this_publication\n                    .typed_data\n                    .value\n                    .collect_module,\n            )),\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n\n    pub fn get_inner_object(&self) -> Result<JsonValue, MomokaVerifierError> {\n        match self {\n            MomokaTransaction::CommentCreated(_) => {\n                let serialized = serde_json::to_string(self)\n                    .map_err(|_| MomokaVerifierError::InvalidSignatureSubmitter)?;\n                let parsed = json::parse(&serialized)\n                    .map_err(|_| MomokaVerifierError::InvalidSignatureSubmitter)?;\n                Ok(parsed[\"CommentCreated\"].clone())\n            }\n            MomokaTransaction::MirrorCreated(_) => {\n                let serialized = serde_json::to_string(self)\n                    .map_err(|_| MomokaVerifierError::InvalidSignatureSubmitter)?;\n                let parsed = json::parse(&serialized)\n                    .map_err(|_| MomokaVerifierError::InvalidSignatureSubmitter)?;\n                Ok(parsed[\"MirrorCreated\"].clone())\n            }\n            MomokaTransaction::PostCreated(_) => {\n                let serialized = serde_json::to_string(self)\n                    .map_err(|_| MomokaVerifierError::InvalidSignatureSubmitter)?;\n                let parsed = json::parse(&serialized)\n                    .map_err(|_| MomokaVerifierError::InvalidSignatureSubmitter)?;\n                Ok(parsed[\"PostCreated\"].clone())\n            }\n            _ => Err(MomokaVerifierError::InvalidTransactionType),\n        }\n    }\n}\n\n/// The `TransactionTimestampProofs` struct represents the timestamp proofs\n/// included with a transaction to verify its authenticity and integrity.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\n#[serde(rename_all = \"camelCase\")]\npub struct TransactionTimestampProofs {\n    /// The type of the transaction provider.\n    #[serde(rename = \"type\")]\n    pub proofs_type: TransactionProvider,\n    /// The hash prefix of the timestamp proofs.\n    pub hash_prefix: String,\n    /// The response object for the timestamp proofs validation.\n    pub response: TransactionTimestampProofsValidation,\n}\n\n/// The `TransactionSummary` struct represents a summary of a transaction,\n/// containing its ID, associated `MomokaTransaction`, and submitter information,\n/// as well as an optional `TimestampProofsResponse` object.\n#[derive(Debug, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub struct TransactionSummary {\n    /// The ID of the transaction.\n    pub id: MomokaTxId,\n    /// The associated `MomokaTransaction`.\n    pub momoka_tx: MomokaTransaction,\n    /// The submitter of the transaction.\n    pub submitter: Address,\n    /// An optional `TimestampProofsResponse` object.\n    pub timestamp_proofs_response: Option<TimestampProofsResponse>,\n    /// The pointer if known!\n    pub pointer_transaction_summary: Option<Box<TransactionSummary>>,\n}\n\nimpl TransactionSummary {\n    /// Sets the `TimestampProofsResponse` object for the transaction summary.\n    pub fn set_timestamp_proofs_response(&mut self, response: TimestampProofsResponse) {\n        self.timestamp_proofs_response = Some(response);\n    }\n\n    /// Sets the `TransactionSummary` for the pointer\n    pub fn set_pointer_transaction_summary(&mut self, response: Box<TransactionSummary>) {\n        self.pointer_transaction_summary = Some(response);\n    }\n}\n\n#[derive(Debug, Deserialize)]\npub struct TransactionError {\n    pub id: MomokaTxId,\n    pub error: MomokaVerifierError,\n}\n\nimpl TransactionError {\n    pub fn new(id: MomokaTxId, error: MomokaVerifierError) -> Self {\n        Self { id, error }\n    }\n}\n"
  },
  {
    "path": "momoka-rs/src/types/verifier_error.rs",
    "content": "use serde::{Deserialize, Serialize};\nuse std::{\n    error::Error,\n    fmt::{Display, Formatter, Result},\n};\nuse strum_macros::EnumString;\n\n#[derive(Debug, EnumString, Clone, PartialEq, Eq, Deserialize, Serialize)]\npub enum MomokaVerifierError {\n    /// This means it has an invalid transaction type\n    InvalidTransactionType,\n    /// This means it has an invalid transaction format and could not parse it (missing data from the object)\n    InvalidTransactionFormat,\n    /// This means the main signature has not been signed by the same payload as the data itself\n    InvalidSignatureSubmitter,\n    /// This means the submitted timestamp proof does not have a valid timestamp proof signature\n    TimestampProofInvalidSignature,\n    /// This means the type in the timestamp proofs do not match timestamp proofs are not portable\n    TimestampProofInvalidType,\n    /// This means the da id in the timestamp proofs do not match up timestamp proofs are not portable\n    TimestampProofInvalidDAID,\n    /// This means the timestamp proof uploaded was not done by a valid submitter\n    TimestampProofNotSubmitter,\n    /// We tried to call them 5 times and its errored out - this is not a bad proof but bundlr/arweave are having issues\n    CannotConnectToBundlr,\n    /// The DA tx could not be found or invalid on the bundlr/arweave nodes can happened if pasted it in wrong\n    InvalidTxID, // NOT USED!\n    /// This the typed data format is invalid (aka a invalid address type etc)\n    InvalidFormattedTypedData,\n    /// This means it can not read the block from the node\n    BlockCantBeReadFromNode,\n    /// This means it can not read the data from the node\n    DataCantBeReadFromNode,\n    /// This means the simulation was not able to be ran on the node, this does not mean that it would fail on chain, it means the nodes may of been down and needs rechecking\n    SimulationNodeCouldNotRun,\n    /// This means the simulation was not successful and got rejected on-chain or the result from the simulation did not match the expected result\n    SimulationFailed,\n    /// This means the event emitted from the simulation does not match the expected event\n    EventMismatch,\n    /// This means the event timestamp passed into the emitted event does not match the signature timestamp\n    InvalidEventTimestamp,\n    /// This means the deadline set in the typed data is not correct\n    InvalidTypedDataDeadlineTimestamp,\n    /// This means the generated publication id for the generic id does not match what it should be\n    GeneratedPublicationIdMismatch,\n    /// This means the pointer set in the chain proofs is not required but set anyway\n    InvalidPointerSetNotNeeded,\n    /// This means the pointer has failed verification\n    PointerFailedVerification,\n    /// This means the block processed against is not the closest block to the timestamp proofs\n    NotClosestBlock,\n    /// This means the timestamp proofs are not close enough to the block\n    BlockTooFar, // NOT USED!\n    /// This means the publication submitted does not have a valid pointer and a pointer is required\n    PublicationNoPointer,\n    /// Some publications (comment and mirror) for now can only be on another DA publication not on evm chain publications\n    PublicationNoneDA,\n    /// This means the publication nonce is invalid at the time of submission\n    PublicationNonceInvalid,\n    /// This means the publication submisson was signed by a wallet that is not allowed\n    PublicationSignerNotAllowed,\n    /// This means the evm signature has already been used Only really starts to be able to be properly used when many submitters\n    ChainSignatureAlreadyUsed,\n    /// This means the publication submisson could not pass potentional due to a reorg\n    PotentialReorg,\n    /// internal cache has broken!\n    CacheError,\n    // bundlr could not find last transaction (most likely API down)\n    NoLastTransactionFound,\n}\n\nimpl Display for MomokaVerifierError {\n    fn fmt(&self, f: &mut Formatter<'_>) -> Result {\n        let error_name = self;\n        write!(f, \"{}\", error_name)\n    }\n}\n\nimpl Error for MomokaVerifierError {}\n\n// Implement the Send trait for your error type\nunsafe impl Send for MomokaVerifierError {}\n"
  },
  {
    "path": "momoka-rs/src/utils.rs",
    "content": "use chrono::Utc;\n\n/// Gets the current UTC time as a formatted string.\n///\n/// The formatted string follows the format \"Tue, 31 May 2022 13:45:00 GMT\".\n///\n/// # Returns\n///\n/// A `String` containing the formatted UTC time.\npub fn get_current_utc_string() -> String {\n    let current_time = Utc::now();\n    let formatted_time = current_time.format(\"%a, %d %b %Y %H:%M:%S GMT\").to_string();\n\n    formatted_time\n}\n"
  },
  {
    "path": "momoka-rs/src/verifier/mod.rs",
    "content": "pub mod proof;\npub mod transactions;\n"
  },
  {
    "path": "momoka-rs/src/verifier/proof.rs",
    "content": "use json::JsonValue;\nuse regex::Regex;\nuse std::{\n    collections::{HashMap, HashSet},\n    str::FromStr,\n    sync::Arc,\n};\n\nuse crate::{\n    bundlr::{\n        api::{get_bulk_transactions_api, get_transaction_api},\n        verify::verify_timestamp_proofs,\n    },\n    cache::{\n        read_signature_cache, read_transaction_cache, set_signature_cache, set_transaction_cache,\n        TransactionCacheResult,\n    },\n    evm::ProviderContext,\n    logger::Logger,\n    submitter::state::is_valid_submitter,\n    types::{\n        transaction::{MomokaTransaction, MomokaTxId, TransactionSummary},\n        verifier_error::MomokaVerifierError,\n    },\n};\nuse ethers::{\n    providers::{Http, Middleware, Provider, RetryClient},\n    types::{Address, Block, BlockNumber, Signature, H256, U256},\n};\n\n/// Returns the block from a slice of three blocks that is closest in time to a specified target timestamp.\n///\n/// # Arguments\n///\n/// * `blocks` - A slice containing three blocks to search through.\n/// * `target_timestamp` - The target timestamp to find the closest block to.\n///\n/// # Returns\n///\n/// An optional `Block` struct containing the closest block, or `None` if the input slice is empty.\n///\n/// # Examples\n///\n/// ```\n/// # use momoka_rs::{Block, get_closest_block};\n/// # use ethers::types::{BlockNumber, H256, U256};\n/// let blocks = [\n///     Block {\n///         hash: H256::zero(),\n///         parent_hash: H256::zero(),\n///         number: BlockNumber::Number(42.into()),\n///         timestamp: U256::from(1620641837),\n///         gas_limit: Default::default(),\n///         gas_used: Default::default(),\n///         miner: Default::default(),\n///         difficulty: Default::default(),\n///         total_difficulty: Default::default(),\n///         size: Default::default(),\n///         extra_data: Default::default(),\n///         transactions: Default::default(),\n///         uncles: Default::default(),\n///         seal_fields: Default::default(),\n///         logs_bloom: Default::default(),\n///         state_root: Default::default(),\n///         receipts_root: Default::default(),\n///         transactions_root: Default::default(),\n///         uncle_hash: Default::default(),\n///     },\n///     Block {\n///         number: BlockNumber::Number(43.into()),\n///         timestamp: U256::from(1620641838),\n///         ..Default::default()\n///     },\n///     Block {\n///         number: BlockNumber::Number(44.into()),\n///         timestamp: U256::from(1620641839),\n///         ..Default::default()\n///     },\n/// ];\n///\n/// let target_timestamp = U256::from(1620641838);\n/// let closest_block = get_closest_block(&blocks, target_timestamp);\n/// assert_eq!(closest_block.unwrap().number, BlockNumber::Number(43.into()));\n/// ```\nfn get_closest_block(blocks: &[Block<H256>; 3], target_timestamp: U256) -> Option<Block<H256>> {\n    let target_timestamp_ms = target_timestamp.as_u64();\n    let target_block_number = BlockNumber::Number(target_timestamp.as_u64().into());\n\n    blocks\n        .iter()\n        .filter(|block| block.number <= target_block_number.as_number())\n        .min_by_key(|block| {\n            let block_timestamp_ms = block.timestamp.as_u64() * 1000;\n            (block_timestamp_ms as i64 - target_timestamp_ms as i64).abs()\n        })\n        .cloned()\n}\n\n/// Fetches blocks with the given block numbers from a specified Ethereum node.\n///\n/// # Arguments\n///\n/// * `block_numbers` - An array containing three block numbers to fetch.\n/// * `provider` - A ethers provider instance\n///\n/// # Returns\n///\n/// An array containing the fetched blocks.\n///\n/// # Errors\n///\n/// Returns a `MomokaVerifierError` if any of the blocks cannot be fetched from the node.\n///\n/// # Examples\n///\n/// ```\n/// # use momoka_rs::get_blocks;\n///\n/// let block_numbers = [42, 43, 44];\n/// let provider =  Provider::<Http>::try_from(node_url).unwrap();\n/// let result = get_blocks(block_numbers, &provider).await;\n/// ```\nasync fn get_blocks(\n    block_numbers: [u64; 3],\n    provider: &Provider<RetryClient<Http>>,\n) -> Result<[Block<H256>; 3], MomokaVerifierError> {\n    let mut blocks = [Default::default(), Default::default(), Default::default()];\n\n    for (i, block_number) in block_numbers.iter().enumerate() {\n        let block = provider\n            .get_block(*block_number)\n            .await\n            .map_err(|_| MomokaVerifierError::BlockCantBeReadFromNode)?\n            .ok_or(MomokaVerifierError::BlockCantBeReadFromNode)?;\n\n        blocks[i] = block;\n    }\n\n    Ok(blocks)\n}\n\n/// Verifies that the block number in a given Momoka transaction matches the closest block to its timestamp.\n///\n/// # Arguments\n///\n/// * `block_number` - A reference to the block number in the Momoka transaction to verify.\n/// * `timestamp` - A reference to the timestamp in the Momoka transaction to use for finding the closest block.\n/// * `provider_context` - The provider context.\n///\n/// # Returns\n///\n/// A `Result<(), MomokaVerifierError>` indicating whether the block number in the Momoka transaction matches the closest block to its timestamp.\n///\n/// # Errors\n///\n/// Returns a `MomokaVerifierError` if any of the following errors occur:\n///\n/// * The block numbers cannot be read from the node.\n/// * The block number in the closest block to the timestamp does not match the given block number, and it is not the next block due to latency.\n/// * The block number in the closest block to the timestamp does not exist.\n///\n/// # Examples\n///\n/// ```\n/// # use momoka_rs::{is_valid_choosen_block, EthereumNode};\n///\n/// let block_number = 42;\n/// let timestamp = 1620627000;\n/// let provider_context = ProviderContext{(/* ... */)};\n/// let result = is_valid_choosen_block(&block_number, &timestamp, &provider_context).await;\n/// ```\nasync fn is_valid_choosen_block(\n    block_number: &u64,\n    timestamp: &u64,\n    provider_context: &ProviderContext,\n) -> Result<(), MomokaVerifierError> {\n    let blocks = get_blocks(\n        [\n            block_number.checked_sub(1).unwrap(),\n            *block_number,\n            block_number.checked_add(1).unwrap(),\n        ],\n        &provider_context.node,\n    )\n    .await?;\n\n    let closest_block = get_closest_block(&blocks, U256::from(*timestamp));\n    if let Some(closest_block) = closest_block {\n        if let Some(closest_block_number) = closest_block.number.map(|n| n.as_u64()) {\n            if closest_block_number != *block_number {\n                // println!(\n                //     \"The block you have chosen is not the closest block to the timestamp.\n                //     The closest block is {} and you have chosen {}.\",\n                //     closest_block_number, block_number\n                // );\n\n                if closest_block_number == block_number.checked_add(1).unwrap_or_default() {\n                    // println!(\"\n                    //     Due to latency with nodes, we allow the next block to be accepted as the closest.\n                    //     When you do a request over the wire, the node provider may not have broadcasted yet,\n                    //     this means you may have 100-300ms latency which cannot be avoided. The signature still\n                    //     needs to conform to the past block, so it's still very valid.\n                    // \");\n                } else {\n                    return Err(MomokaVerifierError::NotClosestBlock);\n                }\n            }\n        } else {\n            return Err(MomokaVerifierError::NotClosestBlock);\n        }\n    } else {\n        return Err(MomokaVerifierError::BlockCantBeReadFromNode);\n    }\n\n    Ok(())\n}\n\n/// the pattern to extract the signature out of the big payload\nconst SIGNATURE_EXTRACT_PATTERN: &str = r#\"\"signature\"\\s*:\\s*\"0x[a-fA-F0-9]{130}\",?\\s*\"#;\n\n/// Extracts the address from a MomokaTransaction.\n///\n/// This function removes the signature from the payload of the transaction,\n/// updates the verifying contract and collect module (if present), and recovers\n/// the address from the signature.\n///\n/// # Arguments\n///\n/// * `transaction` - A reference to the MomokaTransaction from which to extract the address.\n///\n/// # Returns\n///\n/// * `Result<Address, MomokaVerifierError>` - The extracted address if successful, or an error if any step fails.\n///\nfn extract_address(transaction: &MomokaTransaction) -> Result<Address, MomokaVerifierError> {\n    // due to signing a huge payload of typed data we need to remove the signature from the payload\n    // this was due to some calls in the node code and this had some knock on here so we have to do it\n    // a bit dirty! - sorry!!\n\n    let mut inner_object = transaction.get_inner_object()?;\n\n    // Update verifying contract\n    let verifying_contract = transaction.verifying_contract()?;\n    inner_object[\"chainProofs\"][\"thisPublication\"][\"typedData\"][\"domain\"][\"verifyingContract\"] =\n        JsonValue::String(ethers::utils::to_checksum(verifying_contract, None));\n\n    // Update collect module if present\n    if let Some(collect_module) = transaction.typed_data_collect_module()? {\n        let collect_module_checksum = ethers::utils::to_checksum(collect_module, None);\n        inner_object[\"chainProofs\"][\"thisPublication\"][\"typedData\"][\"value\"][\"collectModule\"] =\n            JsonValue::String(collect_module_checksum.clone());\n        inner_object[\"event\"][\"collectModule\"] = JsonValue::String(collect_module_checksum);\n    }\n\n    // Convert the inner object to a JSON string\n    let inner_object_string = json::stringify(inner_object.clone());\n\n    // Remove the signature from the payload\n    let re = Regex::new(SIGNATURE_EXTRACT_PATTERN)\n        .map_err(|_| MomokaVerifierError::InvalidSignatureSubmitter)?;\n    let omit_signature = re.replace(&inner_object_string, \"\").into_owned();\n\n    // Recover the address from the signature\n    let signature = Signature::from_str(transaction.signature()?)\n        .map_err(|_| MomokaVerifierError::InvalidSignatureSubmitter)?;\n\n    let address = signature\n        .recover::<String>(omit_signature)\n        .map_err(|_| MomokaVerifierError::InvalidSignatureSubmitter)?;\n\n    Ok(address)\n}\n\n/// Verifies that the timestamp proofs for a given Momoka transaction match the transaction.\n///\n/// # Arguments\n///\n/// * `momoka_tx` - A reference to the `MomokaTransaction` struct to verify the timestamp proofs for.\n///\n/// # Returns\n///\n/// A `Result<(), MomokaVerifierError>` indicating whether the timestamp proofs match the transaction.\n///\n/// # Examples\n///\n/// ```\n/// # use momoka_rs::{verify_timestamp_proofs_match_transaction, TransactionSummary};\n///\n/// let transaction = TransactionSummary::new(/* ... */);\n/// let result = verify_timestamp_proofs_match_transaction(&transaction).await;\n/// ```\nasync fn verify_timestamp_proofs_match_transaction(\n    transaction: &TransactionSummary,\n) -> Result<(), MomokaVerifierError> {\n    if transaction.timestamp_proofs_response.is_none() {\n        return Err(MomokaVerifierError::TimestampProofInvalidType);\n    }\n\n    if let Some(timestamp_proofs) = transaction.timestamp_proofs_response.as_ref() {\n        if timestamp_proofs.action_type != *transaction.momoka_tx.transaction_type()? {\n            return Err(MomokaVerifierError::TimestampProofInvalidType);\n        }\n\n        if timestamp_proofs.data_availability_id != *transaction.momoka_tx.data_availability_id()? {\n            return Err(MomokaVerifierError::TimestampProofInvalidDAID);\n        }\n    } else {\n        return Err(MomokaVerifierError::TimestampProofInvalidType);\n    }\n\n    verify_timestamp_proofs(&transaction.momoka_tx.get_timestamp_proofs()?.response).await?;\n\n    Ok(())\n}\n\n/// Processes the proof for a given transaction summary.\n///\n/// # Arguments\n///\n/// * `transaction_summary` - A reference to the `TransactionSummary` struct to process the proof for.\n/// * `provider_context` - The provider context.\n///\n/// # Returns\n///\n/// A `Result<(), MomokaVerifierError>` indicating whether the proof was processed successfully.\n///\n/// # Examples\n///\n/// ```\n/// # use momoka_rs::{process_proofs, EthereumNode, TransactionSummary};\n///\n/// let transaction_summary = TransactionSummary::new(/* ... */);\n/// let provider_context = ProviderContext{(/* ... */)};\n/// let result = process_proof(&transaction_summary, &provider_context).await;\n/// ```\nasync fn process_proof(\n    transaction_summary: &TransactionSummary,\n    provider_context: &ProviderContext,\n) -> Result<(), MomokaVerifierError> {\n    let signer_address = extract_address(&transaction_summary.momoka_tx)?;\n\n    if !is_valid_submitter(\n        &provider_context.environment,\n        &signer_address,\n        &provider_context.deployment,\n    ) {\n        println!(\"Invalid submitter\");\n        return Err(MomokaVerifierError::InvalidSignatureSubmitter);\n    }\n\n    if !transaction_summary.momoka_tx.valid_publication_id()? {\n        return Err(MomokaVerifierError::GeneratedPublicationIdMismatch);\n    }\n\n    if !is_valid_submitter(\n        &provider_context.environment,\n        &transaction_summary.submitter,\n        &provider_context.deployment,\n    ) {\n        return Err(MomokaVerifierError::TimestampProofNotSubmitter);\n    }\n\n    if !transaction_summary.momoka_tx.is_valid_event_timestamp()? {\n        return Err(MomokaVerifierError::InvalidEventTimestamp);\n    }\n\n    if !transaction_summary\n        .momoka_tx\n        .is_valid_typed_data_deadline_timestamp()?\n    {\n        return Err(MomokaVerifierError::InvalidTypedDataDeadlineTimestamp);\n    }\n\n    is_valid_choosen_block(\n        transaction_summary.momoka_tx.block_number()?,\n        transaction_summary\n            .momoka_tx\n            .third_party_proofs_timestamp()?,\n        provider_context,\n    )\n    .await?;\n\n    verify_timestamp_proofs_match_transaction(transaction_summary).await?;\n\n    transaction_summary\n        .momoka_tx\n        .validate_transaction(provider_context)\n        .await\n}\n\n/// Retrieves the cached result for a given transaction ID.\n///\n/// This function checks if the transaction ID exists in the cache and returns the cached result\n/// if available. If the transaction ID is not found in the cache, it returns `None`.\n///\n/// # Arguments\n///\n/// * `tx_id` - The transaction ID to check in the cache.\n///\n/// # Returns\n///\n/// * `Result<Option<Result<(), MomokaVerifierError>>` - A `Result` containing `Some(Ok(()))` if the transaction is\n///   cached and successful, `Some(Err(...))` if the transaction is cached but failed, or `None` if the transaction\n///   is not found in the cache.\nfn cached_tx_id(\n    tx_id: &MomokaTxId,\n) -> Result<Option<Result<(), MomokaVerifierError>>, MomokaVerifierError> {\n    let cached: Option<Arc<TransactionCacheResult>> = read_transaction_cache(tx_id);\n\n    if let Some(cached_value) = cached {\n        if !cached_value.success {\n            let error = cached_value\n                .error\n                .clone()\n                .unwrap_or(MomokaVerifierError::CacheError);\n            Ok(Some(Err(error)))\n        } else {\n            Ok(Some(Ok(())))\n        }\n    } else {\n        // not in cache\n        Ok(None)\n    }\n}\n\n/// Sets the cache for a transaction ID with the given result.\n///\n/// This function sets the cache for the provided transaction ID based on the result. If the result\n/// is `Ok(())`, indicating a successful verification, the cache will be set with a success status\n/// and no error. If the result is `Err(...)`, indicating a failed verification with an error,\n/// the cache will be set with a failure status and the error.\n///\n/// # Arguments\n///\n/// * `tx_id` - The transaction ID to set in the cache.\n/// * `result` - The result of the verification, either `Ok(())` for success or `Err(...)` for failure.\n///\n/// # Returns\n///\n/// * `Result<(), MomokaVerifierError>` - A `Result` indicating success if the cache is set successfully.\nfn set_tx_cache(\n    tx_id: MomokaTxId,\n    result: &Result<(), MomokaVerifierError>,\n) -> Result<(), MomokaVerifierError> {\n    let cache_result = TransactionCacheResult {\n        success: result.is_ok(),\n        error: result.clone().err(),\n    };\n\n    set_transaction_cache(tx_id, cache_result);\n\n    Ok(())\n}\n\n/// Checks if the given signature is cached.\n///\n/// # Arguments\n///\n/// * `signature` - The signature to check.\n///\n/// # Returns\n///\n/// A `Result` containing a boolean indicating whether the signature is cached,\n/// or an error if the signature could not be found in the cache.\n///\n/// # Errors\n///\n/// * `MomokaVerifierError::SignatureNotFound` - The signature could not be found in the cache.\nfn cached_signature(signature: &str) -> Result<bool, MomokaVerifierError> {\n    let cached: Option<Arc<()>> = read_signature_cache(signature);\n\n    Ok(cached.is_some())\n}\n\n/// Processes timestamp proofs for a vector of transaction summaries.\n///\n/// # Arguments\n///\n/// * `transactions` - A slice of `TransactionSummary` structs to process proofs for.\n/// * `provider_context` - The provider context.\n///\n/// # Returns\n///\n/// A vector of `Result<(), MomokaVerifierError>` indicating whether each transaction's proof was processed successfully.\n///\n/// # Examples\n///\n/// ```\n/// # use momoka_rs::{process_proofs, EthereumNode, TransactionSummary};\n///\n/// let transactions = vec![/* ... */];\n/// let provider_context = ProviderContext{(/* ... */)};\n/// let results = process_proofs(&transactions, &provider_context).await;\n/// ```\nasync fn process_proofs(\n    mut transactions: Vec<TransactionSummary>,\n    provider_context: &ProviderContext,\n) -> Result<Vec<Result<(), MomokaVerifierError>>, MomokaVerifierError> {\n    // to handle many TCP requests lets bulk grab the data if > 10 requests at once\n    if transactions.len() > 10 {\n        let pointer_tx_ids: HashMap<String, String> = transactions\n            .iter()\n            .filter_map(|transaction| {\n                transaction.momoka_tx.pointer().ok().and_then(|pointer| {\n                    pointer\n                        .as_ref()\n                        .map(|p| (transaction.id.clone(), p.location.replace(\"ar://\", \"\")))\n                })\n            })\n            .collect();\n\n        let pointer_transactions = get_bulk_transactions_api(\n            // remove duplicates as many transactions may point to the same transaction\n            &pointer_tx_ids\n                .values()\n                .cloned()\n                .collect::<HashSet<String>>()\n                .into_iter()\n                .collect::<Vec<String>>(),\n        )\n        .await?;\n\n        for transaction in transactions.iter_mut() {\n            if let Some(pointer_id) = pointer_tx_ids.get(&transaction.id) {\n                if let Some(pointer_transaction) = pointer_transactions\n                    .success\n                    .iter()\n                    .find(|t| t.id == *pointer_id)\n                {\n                    transaction\n                        .set_pointer_transaction_summary(Box::new(pointer_transaction.clone()));\n                }\n            }\n        }\n    }\n\n    let futures = transactions.iter().map(|transaction| async move {\n        if let Some(pointer) = transaction.momoka_tx.pointer()? {\n            let tx_id: &MomokaTxId = &pointer.location.replace(\"ar://\", \"\");\n\n            let cached = cached_tx_id(tx_id)?;\n            if let Some(cached) = cached {\n                cached.unwrap()\n            }\n\n            if transaction.pointer_transaction_summary.is_some() {\n                process_proof(\n                    transaction.pointer_transaction_summary.as_ref().unwrap(),\n                    provider_context,\n                )\n                .await\n                .map_err(|_| MomokaVerifierError::PointerFailedVerification)?;\n            } else {\n                let pointer_transaction = get_transaction_api(tx_id).await?;\n                process_proof(&pointer_transaction, provider_context)\n                    .await\n                    .map_err(|_| MomokaVerifierError::PointerFailedVerification)?;\n            }\n        }\n\n        let tx_cached = cached_tx_id(&transaction.id)?;\n        if let Some(tx_cached) = tx_cached {\n            tx_cached.unwrap()\n        }\n\n        let signature = transaction.momoka_tx.signature()?;\n\n        let seen_signature = cached_signature(signature)?;\n        if seen_signature {\n            return Err(MomokaVerifierError::ChainSignatureAlreadyUsed);\n        }\n\n        let result: Result<(), MomokaVerifierError> =\n            process_proof(transaction, provider_context).await;\n\n        set_signature_cache(signature.to_owned());\n        set_tx_cache(transaction.id.clone(), &result)?;\n\n        match &result {\n            Ok(()) => {\n                Logger.success(&format!(\"{:?} - OK\", transaction.id));\n            }\n            Err(err) => {\n                Logger.error(&format!(\"{:?} -FAILED - {:?}\", transaction.id, err));\n            }\n        }\n\n        result\n    });\n\n    Ok(futures::future::join_all(futures).await)\n}\n\n/// Checks the proofs of a vector of transaction IDs using the provided Ethereum node.\n///\n/// # Arguments\n///\n/// * `tx_ids` - A vector of transaction IDs to check proofs for.\n/// * `provider_context` - The provider context\n///\n/// # Returns\n///\n/// A vector of results, where each result represents the success or failure of checking the proof for\n/// the corresponding transaction ID in the input vector.\n///\n/// # Examples\n///\n/// ```rust\n/// # use momoka_rs::{check_proofs, EthereumNode};\n///\n/// #[tokio::main]\n/// async fn main() {\n///     let tx_ids = vec![\n///         \"dwKu4-ITFVZ_tsYhD0yj2LBYm32LGwiUqpkgg-BDZNE\".to_string(),\n///         \"lwKu4-ITFVZ_tsYhD0yj2LBYm32LGwiUqpkgg-BDZNE\".to_string(),\n///         \"qwKu4-ITFVZ_tsYhD0yj2LBYm32LGwiUqpkgg-BDZNE\".to_string(),\n///     ];\n///\n///     let provider_context = ProviderContext{(/* ... */)};\n///\n///     let results = check_proofs(&tx_ids, &provider_context).await;\n///\n///     for result in results {\n///         match result {\n///             Ok(_) => println!(\"Proof check succeeded\"),\n///             Err(e) => println!(\"Proof check failed: {:?}\", e),\n///         }\n///     }\n/// }\n/// ```\npub async fn check_proofs(\n    tx_ids: &Vec<MomokaTxId>,\n    provider_context: &ProviderContext,\n) -> Result<Vec<Result<(), MomokaVerifierError>>, MomokaVerifierError> {\n    let amount = tx_ids.len();\n    let is_bulk = amount > 999;\n    if is_bulk {\n        Logger.info(&format!(\"Fetching {} transactions from bundlr\", amount));\n    }\n\n    let transactions = get_bulk_transactions_api(tx_ids).await?;\n\n    if is_bulk {\n        Logger.info(&format!(\"Fetched {} transactions from bundlr\", amount));\n    }\n\n    for (id, error) in transactions.failed {\n        Logger.error(&format!(\"{:?} - FAILED - {:?}\", id, error));\n    }\n\n    Logger.info(&format!(\"Checking proofs for {} transactions\", amount));\n\n    process_proofs(transactions.success, provider_context).await\n}\n\n/// Asynchronously checks the proof for a single transaction ID and returns the result.\n///\n/// This method calls the `check_proofs` function internally with a single transaction ID and\n/// returns the result of the first transaction. If the proof check is successful for the transaction,\n/// it returns `Ok(())`. Otherwise, an appropriate error variant is returned.\n///\n/// # Arguments\n///\n/// * `tx_id` - A string slice representing the transaction ID to check the proof for.\n/// * `provider_context` - A reference to the `ProviderContext` containing the necessary provider information.\n///\n/// # Returns\n///\n/// * `Ok(())` if the proof check is successful for the first transaction.\n/// * An `Err` containing the appropriate `MomokaVerifierError` if the proof check fails for the first transaction,\n///   or if the transaction ID is not found in the `check_proofs` results.\npub async fn check_proof(\n    tx_id: &MomokaTxId,\n    provider_context: &ProviderContext,\n) -> Result<(), MomokaVerifierError> {\n    let results = check_proofs(&vec![tx_id.to_string()], provider_context).await?;\n\n    // Get the first result or return an error if the transaction ID is not found\n    match results.get(0) {\n        Some(Ok(())) => Ok(()),\n        Some(Err(err)) => Err(err.clone()),\n        None => panic!(\"Could not find the tx {:?}\", tx_id),\n    }\n}\n"
  },
  {
    "path": "momoka-rs/src/verifier/transactions/comment.rs",
    "content": "use crate::{\n    contracts::lens_hub::get_profile_details,\n    environment::environment_to_lens_hub_contract,\n    evm::ProviderContext,\n    types::{\n        eip721::{CreateCommentEIP712TypedData, CreateCommentEIP712TypedDataValue},\n        evm_event::CommentCreatedEventEmittedResponse,\n        transaction::{CommentCreatedPublication, TransactionPointerType},\n        verifier_error::MomokaVerifierError,\n    },\n};\nuse ethers::types::{Address, U256};\n\nuse super::common::recovery_signed_typed_data;\n\n/// Retrieves the address of the signer who signed the given comment typed data using the provided signature.\n///\n/// # Arguments\n///\n/// * `signature` - The signature of the signer.\n/// * `typed_data` - The comment typed data containing the domain, types, and value.\n///\n/// # Returns\n///\n/// The address of the signer on success, or an error of type `MomokaVerifierError` if the operation fails.\nfn who_signed_typed_data(\n    signature: &str,\n    typed_data: &CreateCommentEIP712TypedData,\n) -> Result<Address, MomokaVerifierError> {\n    recovery_signed_typed_data(\n        signature,\n        &typed_data.domain.to_ethers_type(),\n        &typed_data.types.comment_with_sig,\n        &typed_data.value,\n        \"CommentWithSig\".to_string(),\n    )\n}\n\n/// Cross-checks the event emitted in the CommentCreated transaction\n/// with the provided pub_count_at_block and typed_data.\n///\n/// # Arguments\n///\n/// * `event` - The CommentCreatedEventEmittedResponse event to cross-check.\n/// * `pub_count_at_block` - The pub_count_at_block value to compare with the event's pub_id.\n/// * `value` - The CreateCommentEIP712TypedDataValue to compare with the event's fields.\n///\n/// # Returns\n///\n/// * `Result<(), MomokaVerifierError>` - Ok(()) if the cross-check passes, or an Err indicating the mismatch.\nfn cross_check_event(\n    event: &CommentCreatedEventEmittedResponse,\n    pub_count_at_block: &U256,\n    value: &CreateCommentEIP712TypedDataValue,\n) -> Result<(), MomokaVerifierError> {\n    // Compare the fields of typed_data with the corresponding fields in the event\n    if value.profile_id != event.profile_id\n        || value.content_uri != event.content_uri\n        || value.profile_id_pointed != event.profile_id_pointed\n        || value.pub_id_pointed != event.pub_id_pointed\n        || value.collect_module != event.collect_module\n        || !event.collect_module_return_data.is_empty()\n        || value.reference_module != event.reference_module\n        || !value.reference_module_data.is_empty()\n        || !event.reference_module_return_data.is_empty()\n        || !value.collect_module_init_data.is_empty()\n        || !value.reference_module_init_data.is_empty()\n    {\n        return Err(MomokaVerifierError::EventMismatch);\n    }\n\n    // Check if the pub_count_at_block + 1 matches the event's pub_id\n    if *pub_count_at_block + U256::one() != event.pub_id.clone().into() {\n        return Err(MomokaVerifierError::EventMismatch);\n    }\n\n    // Cross-check passed\n    Ok(())\n}\n\n/// Verifies the comment created publication.\n///\n/// This function performs various verification checks on the provided `CommentCreatedPublication` to ensure its validity.\n/// It checks if the publication has a valid pointer, if the pointer type is on the Data Availability (DA) chain,\n/// verifies the signature of the publication, checks the profile details, validates the nonce,\n/// and cross-checks the event with the profile's current publication ID.\n///\n/// # Arguments\n///\n/// * `publication` - A reference to the `CommentCreatedPublication` to be verified.\n/// * `provider_context` - The ethers provider.\n///\n/// # Returns\n///\n/// * `Result<(), MomokaVerifierError>` - A result indicating success or failure. If the verification is successful, `Ok(())` is returned.\n///   Otherwise, an `Err` variant of `MomokaVerifierError` is returned.\n///\n/// # Errors\n///\n/// The function can return the following errors:\n///\n/// * `PublicationNoPointer` - If the publication does not have a pointer.\n/// * `PublicationNoneDA` - If the pointer type is not on the Data Availability (DA) chain.\n/// * `PublicationNonceInvalid` - If the signature nonce does not match the publication nonce.\n/// * `PublicationSignerNotAllowed` - If the signer address is not allowed based on the profile details.\n/// * `EventMismatch` - If the event fails to cross-check with the profile's current publication ID.\n/// * `GetProfileDetailsError` - If there is an error retrieving profile details from the Ethereum node.\n/// * `WhoSignedTypedDataError` - If there is an error verifying the signature of the publication.\n///\npub async fn verifier_comment(\n    publication: &CommentCreatedPublication,\n    provider_context: &ProviderContext,\n) -> Result<(), MomokaVerifierError> {\n    let pointer = publication\n        .chain_proofs\n        .pointer\n        .as_ref()\n        .ok_or(MomokaVerifierError::PublicationNoPointer)?;\n\n    if pointer.pointer_type != TransactionPointerType::OnDa {\n        return Err(MomokaVerifierError::PublicationNoneDA);\n    }\n\n    let typed_data = publication.typed_data();\n\n    let address: Address = who_signed_typed_data(publication.signature(), typed_data)?;\n\n    let profile_details = get_profile_details(\n        environment_to_lens_hub_contract(&provider_context.environment).unwrap(),\n        publication.profile_id(),\n        address,\n        publication.chain_proofs.this_publication.block_number,\n        &provider_context.node,\n    )\n    .await?;\n\n    if &profile_details.sig_nonce.as_u64() != publication.nonce()\n        || (profile_details.dispatcher_address != address\n            && profile_details.owner_of_address != address)\n    {\n        return Err(MomokaVerifierError::PublicationNonceInvalid);\n    }\n\n    cross_check_event(\n        &publication.event,\n        &profile_details.current_publication_id,\n        &typed_data.value,\n    )?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "momoka-rs/src/verifier/transactions/common.rs",
    "content": "use std::{collections::BTreeMap, str::FromStr};\n\nuse ethers::types::{\n    transaction::eip712::{EIP712Domain, Eip712, Eip712DomainType, TypedData},\n    Address, Signature,\n};\nuse serde::Serialize;\nuse serde_json::Value;\n\nuse crate::types::verifier_error::MomokaVerifierError;\n\n/// Recovers the address from a signed typed data using a given signature.\n///\n/// # Arguments\n///\n/// * `signature` - The signature to recover the address from.\n/// * `domain` - The EIP712 domain parameters.\n/// * `types` - The list of EIP712 domain types.\n/// * `value` - The value representing the typed data.\n/// * `primary_type_name` - The primary type name used for the typed data.\n///\n/// # Returns\n///\n/// The recovered address on success, or an error of type `MomokaVerifierError` if the\n/// operation fails.\npub fn recovery_signed_typed_data<TValue: Serialize>(\n    signature: &str,\n    domain: &EIP712Domain,\n    types: &[Eip712DomainType],\n    value: &TValue,\n    primary_type_name: String,\n) -> Result<Address, MomokaVerifierError> {\n    let mut types_map = BTreeMap::new();\n    types_map.insert(primary_type_name.to_owned(), types.to_vec());\n\n    let message: BTreeMap<String, Value> = serde_json::from_str(\n        &serde_json::to_string(value)\n            .map_err(|_| MomokaVerifierError::InvalidFormattedTypedData)?,\n    )\n    .map_err(|_| MomokaVerifierError::InvalidFormattedTypedData)?;\n\n    let typed_data: TypedData = TypedData {\n        domain: domain.clone(),\n        types: types_map,\n        primary_type: primary_type_name,\n        message,\n    };\n\n    let hash = typed_data\n        .encode_eip712()\n        .map_err(|_| MomokaVerifierError::InvalidFormattedTypedData)?;\n\n    let signature = Signature::from_str(signature)\n        .map_err(|_| MomokaVerifierError::InvalidFormattedTypedData)?;\n\n    let address = signature\n        .recover(hash)\n        .map_err(|_| MomokaVerifierError::InvalidFormattedTypedData)?;\n\n    Ok(address)\n}\n"
  },
  {
    "path": "momoka-rs/src/verifier/transactions/mirror.rs",
    "content": "use crate::{\n    contracts::lens_hub::get_profile_details,\n    environment::environment_to_lens_hub_contract,\n    evm::ProviderContext,\n    types::{\n        eip721::{CreateMirrorEIP712TypedData, CreateMirrorEIP712TypedDataValue},\n        evm_event::MirrorCreatedEventEmittedResponse,\n        transaction::{MirrorCreatedPublication, TransactionPointerType},\n        verifier_error::MomokaVerifierError,\n    },\n};\nuse ethers::types::{Address, U256};\n\nuse super::common::recovery_signed_typed_data;\n\n/// Retrieves the address of the signer who signed the given mirror typed data using the provided signature.\n///\n/// # Arguments\n///\n/// * `signature` - The signature of the signer.\n/// * `typed_data` - The mirror typed data containing the domain, types, and value.\n///\n/// # Returns\n///\n/// The address of the signer on success, or an error of type `MomokaVerifierError` if the operation fails.\nfn who_signed_typed_data(\n    signature: &str,\n    typed_data: &CreateMirrorEIP712TypedData,\n) -> Result<Address, MomokaVerifierError> {\n    recovery_signed_typed_data(\n        signature,\n        &typed_data.domain.to_ethers_type(),\n        &typed_data.types.mirror_with_sig,\n        &typed_data.value,\n        \"MirrorWithSig\".to_string(),\n    )\n}\n\n/// Cross-checks the event emitted in the MirrorCreated transaction\n/// with the provided pub_count_at_block and typed_data.\n///\n/// # Arguments\n///\n/// * `event` - The MirrorCreatedEventEmittedResponse event to cross-check.\n/// * `pub_count_at_block` - The pub_count_at_block value to compare with the event's pub_id.\n/// * `value` - The CreateMirrorEIP712TypedDataValue to compare with the event's fields.\n///\n/// # Returns\n///\n/// * `Result<(), MomokaVerifierError>` - Ok(()) if the cross-check passes, or an Err indicating the mismatch.\nfn cross_check_event(\n    event: &MirrorCreatedEventEmittedResponse,\n    pub_count_at_block: &U256,\n    value: &CreateMirrorEIP712TypedDataValue,\n) -> Result<(), MomokaVerifierError> {\n    if value.profile_id != event.profile_id\n        || value.profile_id_pointed != event.profile_id_pointed\n        || value.pub_id_pointed != event.pub_id_pointed\n        || value.reference_module != event.reference_module\n        || !value.reference_module_data.is_empty()\n        || !event.reference_module_return_data.is_empty()\n        || !event.reference_module_return_data.is_empty()\n        || !value.reference_module_init_data.is_empty()\n    {\n        return Err(MomokaVerifierError::EventMismatch);\n    }\n\n    if pub_count_at_block + U256::one() != event.pub_id.clone().into() {\n        return Err(MomokaVerifierError::EventMismatch);\n    }\n\n    Ok(())\n}\n\n/// Verifies the mirror created publication.\n///\n/// This function performs various verification checks on the provided `MirrorCreatedPublication` to ensure its validity.\n/// It checks if the publication has a valid pointer, if the pointer type is on the Data Availability (DA) chain,\n/// verifies the signature of the publication, checks the profile details, validates the nonce,\n/// and cross-checks the event with the profile's current publication ID.\n///\n/// # Arguments\n///\n/// * `publication` - A reference to the `MirrorCreatedPublication` to be verified.\n/// * `provider_context` - The provider context.\n///\n/// # Returns\n///\n/// * `Result<(), MomokaVerifierError>` - A result indicating success or failure. If the verification is successful, `Ok(())` is returned.\n///   Otherwise, an `Err` variant of `MomokaVerifierError` is returned.\n///\n/// # Errors\n///\n/// The function can return the following errors:\n///\n/// * `PublicationNoPointer` - If the publication does not have a pointer.\n/// * `PublicationNoneDA` - If the pointer type is not on the Data Availability (DA) chain.\n/// * `PublicationNonceInvalid` - If the signature nonce does not match the publication nonce.\n/// * `PublicationSignerNotAllowed` - If the signer address is not allowed based on the profile details.\n/// * `EventMismatch` - If the event fails to cross-check with the profile's current publication ID.\n/// * `GetProfileDetailsError` - If there is an error retrieving profile details from the Ethereum node.\n/// * `WhoSignedTypedDataError` - If there is an error verifying the signature of the publication.\n///\npub async fn verifier_mirror(\n    publication: &MirrorCreatedPublication,\n    provider_context: &ProviderContext,\n) -> Result<(), MomokaVerifierError> {\n    let pointer = publication\n        .chain_proofs\n        .pointer\n        .as_ref()\n        .ok_or(MomokaVerifierError::PublicationNoPointer)?;\n\n    if pointer.pointer_type != TransactionPointerType::OnDa {\n        return Err(MomokaVerifierError::PublicationNoneDA);\n    }\n\n    let typed_data = publication.typed_data();\n\n    let address: Address = who_signed_typed_data(publication.signature(), typed_data)?;\n\n    let profile_details = get_profile_details(\n        environment_to_lens_hub_contract(&provider_context.environment).unwrap(),\n        publication.profile_id(),\n        address,\n        publication.chain_proofs.this_publication.block_number,\n        &provider_context.node,\n    )\n    .await?;\n\n    if &profile_details.sig_nonce.as_u64() != publication.nonce() {\n        return Err(MomokaVerifierError::PublicationNonceInvalid);\n    }\n\n    if profile_details.dispatcher_address != address && profile_details.owner_of_address != address\n    {\n        return Err(MomokaVerifierError::PublicationSignerNotAllowed);\n    }\n\n    cross_check_event(\n        &publication.event,\n        &profile_details.current_publication_id,\n        &typed_data.value,\n    )?;\n\n    Ok(())\n}\n"
  },
  {
    "path": "momoka-rs/src/verifier/transactions/mod.rs",
    "content": "pub mod comment;\nmod common;\npub mod mirror;\npub mod post;\n"
  },
  {
    "path": "momoka-rs/src/verifier/transactions/post.rs",
    "content": "use crate::contracts::lens_hub::{lens_hub_contract, Eip712Signature, ILensHub, PostWithSigData};\nuse crate::environment::environment_to_lens_hub_contract;\nuse crate::evm::{parse_signature, ProviderContext};\nuse crate::types::eip721::CreatePostEIP712TypedDataValue;\nuse crate::types::evm_event::PostCreatedEventEmittedResponse;\nuse crate::types::profile_id::ProfileId;\nuse crate::types::{transaction::PostCreatedPublication, verifier_error::MomokaVerifierError};\n\nuse ethers::prelude::*;\nuse ethers::types::U256;\n\n/// Simulates a transaction by calling the appropriate method on the Lens Hub contract.\n///\n/// This function takes a `PostCreatedPublication` and simulates the transaction by constructing\n/// the necessary parameters and making the corresponding contract call on the Lens Hub contract.\n/// The simulation result is returned as a `U256`.\n///\n/// # Arguments\n///\n/// * `lens_hub` - An instance of `ILensHub` representing the Lens Hub contract.\n/// * `publication` - A reference to the `PostCreatedPublication` to be simulated.\n///\n/// # Returns\n///\n/// * A `Result` containing the simulation result as a `U256` on success,\n///   or a `MomokaVerifierError` if the simulation failed or the data couldn't be read from the node.\n///\n/// # Examples\n///\n/// ```rust\n/// let lens_hub = lens_hub_contract(&lens_hub_address, &provider);\n/// let publication = PostCreatedPublication::new(...);\n///\n/// let simulation_result = simulate_transaction(&lens_hub, &publication).await;\n///\n/// match simulation_result {\n///     Ok(result) => {\n///         println!(\"Simulation result: {}\", result);\n///     }\n///     Err(error) => {\n///         println!(\"Failed to simulate transaction: {:?}\", error);\n///     }\n/// }\n/// ```\nasync fn simulate_transaction(\n    lens_hub: &ILensHub<&Provider<RetryClient<Http>>>,\n    publication: &PostCreatedPublication,\n) -> Result<U256, MomokaVerifierError> {\n    let typed_data_value = publication.typed_data_value().clone();\n\n    let sig = parse_signature(\n        &publication.chain_proofs.this_publication.signature,\n        typed_data_value.deadline,\n    )?;\n\n    let sig_request = PostWithSigData {\n        profile_id: publication.profile_id().clone().into(),\n        content_uri: typed_data_value.content_uri.clone(),\n        collect_module: typed_data_value.collect_module,\n        collect_module_init_data: typed_data_value.collect_module_init_data.clone().into(),\n        reference_module: typed_data_value.reference_module,\n        reference_module_init_data: typed_data_value.reference_module_init_data.clone().into(),\n        sig: Eip712Signature {\n            v: sig.v,\n            r: sig.r,\n            s: sig.s,\n            deadline: sig.deadline.into(),\n        },\n    };\n\n    let block_number = publication.chain_proofs.this_publication.block_number;\n\n    let result: U256 = if publication.chain_proofs.this_publication.signed_by_delegate {\n        lens_hub\n            .post_with_sig_dispatcher(sig_request)\n            .block(block_number)\n            .call()\n            .await\n            .map_err(|_| MomokaVerifierError::DataCantBeReadFromNode)?\n    } else {\n        lens_hub\n            .post_with_sig(sig_request)\n            .block(block_number)\n            .call()\n            .await\n            .map_err(|_| MomokaVerifierError::DataCantBeReadFromNode)?\n    };\n\n    Ok(result)\n}\n\n/// Retrieves the expected simulation result from the Lens Hub contract.\n///\n/// This function queries the Lens Hub contract using the provided profile ID and block number\n/// to retrieve the publication count. It then increments the result by one and returns it as a `U256`.\n///\n/// # Arguments\n///\n/// * `lens_hub` - An instance of `ILensHub` representing the Lens Hub contract.\n/// * `profile_id` - A reference to the `ProfileId` for which the publication count is retrieved.\n/// * `block_number` - A reference to the block number at which the simulation is performed.\n///\n/// # Returns\n///\n/// * A `Result` containing the expected simulation result as a `U256` on success,\n///   or a `MomokaVerifierError` if the data couldn't be read from the node.\n///\n/// # Examples\n///\n/// ```rust\n/// let lens_hub = lens_hub_contract(&lens_hub_address, &provider);\n/// let profile_id = ProfileId::new(...);\n/// let block_number = 1000u64;\n///\n/// let result = get_expected_simulation_result(&lens_hub, &profile_id, &block_number).await;\n///\n/// match result {\n///     Ok(simulation_result) => {\n///         println!(\"Expected simulation result: {}\", simulation_result);\n///     }\n///     Err(error) => {\n///         println!(\"Failed to retrieve simulation result: {:?}\", error);\n///     }\n/// }\n/// ```\nasync fn get_expected_simulation_result(\n    lens_hub: &ILensHub<&Provider<RetryClient<Http>>>,\n    profile_id: &ProfileId,\n    block_number: u64,\n) -> Result<U256, MomokaVerifierError> {\n    let result: U256 = lens_hub\n        .get_pub_count(profile_id.clone().into())\n        .block(block_number)\n        .call()\n        .await\n        .map_err(|_| MomokaVerifierError::DataCantBeReadFromNode)?;\n\n    Ok(result + U256::from(1u64))\n}\n\n/// Cross-checks the event data with the simulated publication result and typed data.\n///\n/// This function verifies the consistency of the event data by comparing it with the\n/// simulated publication result and the corresponding typed data. It checks if the event\n/// data matches the expected values for the profile ID, content URI, modules, and return data.\n///\n/// # Arguments\n///\n/// * `event` - The event emitted during the publication.\n/// * `simulated_pub_result` - The simulated publication result.\n/// * `value` - The typed data value used for the publication.\n///\n/// # Errors\n///\n/// This function returns an error if the event data does not match the expected values,\n/// indicating an event mismatch.\n///\n/// # Examples\n///\n/// ```\n/// let event = create_post_event();\n/// let simulated_pub_result = simulate_publication();\n/// let typed_data = create_typed_data();\n///\n/// if let Err(err) = cross_check_event(&event, simulated_pub_result, &typed_data) {\n///     println!(\"Event data cross-check failed: {:?}\", err);\n/// }\n/// ```\nfn cross_check_event(\n    event: &PostCreatedEventEmittedResponse,\n    simulated_pub_result: U256,\n    value: &CreatePostEIP712TypedDataValue,\n) -> Result<(), MomokaVerifierError> {\n    if simulated_pub_result != event.pub_id.clone().into()\n        || value.profile_id != event.profile_id\n        || value.content_uri != event.content_uri\n        || value.collect_module != event.collect_module\n        || !event.collect_module_return_data.is_empty()\n        || value.reference_module != event.reference_module\n        || !event.reference_module_return_data.is_empty()\n        || !value.collect_module_init_data.is_empty()\n        || !value.reference_module_init_data.is_empty()\n    {\n        return Err(MomokaVerifierError::EventMismatch);\n    }\n\n    Ok(())\n}\n\n/// Verifies the integrity and consistency of a post publication.\n///\n/// This function performs a series of verification steps to ensure the correctness\n/// of the post publication. It checks the signature, simulates the transaction,\n/// verifies the simulation result, and cross-checks the event data.\n///\n/// # Arguments\n///\n/// * `publication` - The post created publication to be verified.\n/// * `provider_context` - The provider context used for simulation and block retrieval.\n///\n/// # Errors\n///\n/// This function returns an error if any of the verification steps fail. The possible\n/// error types include:\n///\n/// * `InvalidPointerSetNotNeeded` - Indicates that the pointer set is invalid and not needed.\n/// * `SimulationFailed` - Indicates that the simulation of the transaction failed.\n/// * `PotentialReorg` - Indicates a potential reorganization of the blockchain.\n/// * `CrossCheckFailed` - Indicates that the cross-check of the event data failed.\n///\n/// # Examples\n///\n/// ```\n/// let publication = create_post_publication();\n/// let provider_context = create_provider_context();\n///\n/// if let Err(err) = verifier_post(&publication, &provider_context) {\n///     println!(\"Publication verification failed: {:?}\", err);\n/// }\n/// ```\npub async fn verifier_post(\n    publication: &PostCreatedPublication,\n    provider_context: &ProviderContext,\n) -> Result<(), MomokaVerifierError> {\n    if publication.chain_proofs.pointer.is_some() {\n        return Err(MomokaVerifierError::InvalidPointerSetNotNeeded);\n    }\n\n    let lens_hub = lens_hub_contract(\n        environment_to_lens_hub_contract(&provider_context.environment).unwrap(),\n        provider_context.node.provider(),\n    );\n\n    let simulation_result = simulate_transaction(&lens_hub, publication).await?;\n\n    let expected_simulation_result = get_expected_simulation_result(\n        &lens_hub,\n        publication.profile_id(),\n        publication.chain_proofs.this_publication.block_number,\n    )\n    .await?;\n\n    if simulation_result != expected_simulation_result {\n        let result = provider_context\n            .node\n            .get_block(publication.chain_proofs.this_publication.block_hash)\n            .await;\n\n        match result {\n            Ok(_block) => {\n                return Err(MomokaVerifierError::SimulationFailed);\n            }\n            Err(_err) => {\n                return Err(MomokaVerifierError::PotentialReorg);\n            }\n        }\n    }\n\n    cross_check_event(\n        &publication.event,\n        simulation_result,\n        publication.typed_data_value(),\n    )?;\n\n    Ok(())\n}\n"
  }
]