xanoutas/solidity-security-findings huggingface dataset:
GenericRegistry#tokenURI breaks eip-721 standard
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/registries/contracts/GenericRegistry.sol#L135-L141


# Vulnerability details

If an erc721 token (or in this case unitId) doesn't exists its `tokenURI` should throw/revert. In case of the GenericRegistry eip-721 implementation it does not.

## Impact

The `GenericRegistry` doesn't satisfy the [eip-721](https://eips.ethereum.org/EIPS/eip-721) standard.

```solidity
    /// @notice A distinct Uniform Resource Identifier (URI) for a given asset.
    /// @dev Throws if `_tokenId` is not a valid NFT. URIs are defined in RFC
    ///  3986. The URI may point to a JSON file that conforms to the "ERC721
    ///  Metadata JSON Schema".
    function tokenURI(uint256 _tokenId) external view returns (string);
```

## Proof of Concept

The implementation of GenericRegistry#tokenURI doesn't follow the eip-721 standard:

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/registries/contracts/GenericRegistry.sol#L135-L141

Add the following POC to (`ComponentRegistry.js` test file) :

The POC will show that the call will not revert on non-existent unitId breaking eip-721 standard

```javascript
        it("tokenUri workings", async function () {
            const mechManager = signers[1];
            const user = signers[2];
            const tokenId = 1;
            await componentRegistry.changeManager(mechManager.address);
            await componentRegistry.connect(mechManager).create(user.address, componentHash, dependencies);
            expect(await componentRegistry.balanceOf(user.address)).to.equal(1);
            expect(await componentRegistry.exists(tokenId)).to.equal(true);
            
            const totalSupply = (await componentRegistry.totalSupply()).toNumber();
            expect(totalSupply == 1);

            expect(await componentRegistry.exists(99)).to.equal(false);

            // @-> tokenUri should throw on non existent ...
            componentRegistry.tokenURI(99);
        });
```

```bash
npx hardhat test  --grep "tokenUri"

ComponentRegistry
    Component creation
      ✔ tokenUri workings
    
    1 passing (1s)

```

## Tools Used
Manual review

## Recommended Mitigation Steps

Inside `tokeURI` use `GenericRegistry#exists` function logic to verify `unitId` existence and revert in the case it doesn't exists.

```diff
    function tokenURI(uint256 unitId) public view virtual override returns (string memory) {
+       // copied from exist external method
+       bool exists = unitId > 0 && unitId < (totalSupply + 1);
+       if (!exists) revert WrongUnitId(msg.sender, unitId);
+        
        bytes32 unitHash = _getUnitHash(unitId);
        // Parse 2 parts of bytes32 into left and right hex16 representation, and concatenate into string
        // adding the base URI and a cid prefix for the full base16 multibase prefix IPFS hash representation
        return string(abi.encodePack
DoS Vulnerability Due to Lack of Permission Checks in Polygon fx-portal Tunnel Configuration
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/main/governance/contracts/bridges/FxERC20ChildTunnel.sol#L24
https://github.com/code-423n4/2023-12-autonolas/blob/main/governance/contracts/bridges/FxERC20RootTunnel.sol#L24


# Vulnerability details

## Impact
The availability of the protocol can be compromised.

## Proof of Concept
In the FxERC20ChildTunnel, inheriting from FxBaseChildTunnel, the setFxRootTunnel function is defined as follows:

```solidity
// set fxRootTunnel if not set already
function setFxRootTunnel(address _fxRootTunnel) external virtual {
    require(fxRootTunnel == address(0x0), "FxBaseChildTunnel: ROOT_TUNNEL_ALREADY_SET");
    fxRootTunnel = _fxRootTunnel;
}
```

Similarly, in the FxERC20RootTunnel, inheriting from FxBaseRootTunnel, the setFxChildTunnel function is:

```solidity
// set fxChildTunnel if not set already
function setFxChildTunnel(address _fxChildTunnel) public virtual {
    require(fxChildTunnel == address(0x0), "FxBaseRootTunnel: CHILD_TUNNEL_ALREADY_SET");
    fxChildTunnel = _fxChildTunnel;
}
```
The FxERC20ChildTunnel Contract is deployed on L2 (Polygon), and the FxERC20RootTunnel Contract is deployed on L1 (Ethereum). In the FxERC20ChildTunnel Contract, fxRootTunnel points to the FxERC20RootTunnel Contract address on L1, and in the FxERC20RootTunnel Contract, it points to the FxERC20ChildTunnel Contract address on L2. If these addresses are arbitrarily manipulated by a front runner, it can compromise the protocol's availability.


## Tools Used
Manual Audit

## Recommended Mitigation Steps
The setFxRootTunnel and setFxChildTunnel functions in FxERC20ChildTunnel and FxERC20RootTunnel, which inherit from FxBaseChildTunnel and FxBaseRootTunnel respectively, should be redefined to restrict access to authorized users only.

Alternatively, the fxRootTunnel in FxERC20ChildTunnel should be defined in the constructor when deployed, and the fxChildTunnel in FxERC20RootTunnel should be similarly defined in the constructor upon deployment.


## Assessed type

DoS
GuardCM cannot be used o newer Gnosis safe wallet version
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/governance/test/GuardCM.js#L265


# Vulnerability details

`GuardCM` contract is intended to be used as a guard module for a gnosis Safe wallet.
Its implementation will not work with gnosis Safe that is newer then 1.3.0 version

## Impact

The `GuardCM` cannot be added to a Gnosis Safe wallet that is newer than 1.3.0 version.

## Proof of Concept

for newer versions this guard/module can not be successfully added with the call to `GnosisSafe#setGuard`. On a newer wallet versions the Guard contract needs to inherit the IERC165 functionality.

Note : a call to `setGuard` is used inside the tests to add the guard to a already existing safe:
https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/governance/test/GuardCM.js#L265

In version 1.3.0 there is no need for `Guard` module to support IERC165:

https://github.com/safe-global/safe-contracts/blob/186a21a74b327f17fc41217a927dea7064f74604/contracts/base/GuardManager.sol#L34-L36

But beginning from 1.4.0

https://github.com/safe-global/safe-contracts/blob/e870f514ad34cd9654c72174d6d4a839e3c6639f/contracts/base/GuardManager.sol#L53-L56

and latest 1.5.0:

https://github.com/safe-global/safe-contracts/blob/810fad9a074837e1247ca24ac9e7f77a5dffce19/contracts/base/GuardManager.sol#L88-L91


The Guard contract module needs to support IERC165 functionality otherwise will revers with `GS300` error.


## Tools Used
Manual review

## Recommended Mitigation Steps

Add IERC165 interface support to the `GuardCM` contract.

Or directly use the `BaseGuard` provided by Gnosis Safe:

https://github.com/safe-global/safe-contracts/blob/f03dfae65fd1d085224b00a10755c509a4eaacfe/contracts/base/GuardManager.sol#L61-L67


## Assessed type

Other
Missing slippage protection in `liquidity_lockbox::withdraw`
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L277


# Vulnerability details

## Impact

Vanilla example of missing slippage protection.

## Proof of Concept

As any AMM, Orca implements slippage protections by letting the caller specify the minimum amount of input and output tokens to be used in a given operation, so that if the transaction outputs a value less than the expected ones, it will revert preventing users from incurring in unacceptable losses.

In our situation, we are interested in the `decreaseLiquidity` handler:

[**decrease_liquidity, lines 18 and 19**](https://github.com/orca-so/whirlpools/blob/3206c9cdfbf27c73c30cbcf5b6df2929cbf87618/programs/whirlpool/src/instructions/decrease_liquidity.rs#L18C1-L19C22)

```rs
pub fn handler(
    ctx: Context<ModifyLiquidity>,
    liquidity_amount: u128,
    token_min_a: u64,
    token_min_b: u64,
) -> Result<()> {
    
    ...

    let (delta_a, delta_b) = calculate_liquidity_token_deltas(
        ctx.accounts.whirlpool.tick_current_index,
        ctx.accounts.whirlpool.sqrt_price,
        &ctx.accounts.position,
        liquidity_delta,
    )?;

    if delta_a < token_min_a {
        return Err(ErrorCode::TokenMinSubceeded.into());
    } else if delta_b < token_min_b {
        return Err(ErrorCode::TokenMinSubceeded.into());
    }

    ...
}
```

The code snippet above calculates the delta variations of the two tokens amount in the given pool and reverts the whole transaction if the calculated amounts are less than the specified ones. However, if we go to

[**liquidity_lockbox, function withdraw**](https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L277)

```solidity
        ...

        whirlpool.decreaseLiquidity{accounts: metasDecreaseLiquidity, seeds: [[pdaProgramSeed, pdaBump]]}(amount, 0, 0);

        ...
```

we see that `token_min_a` and `token_min_b` are hard-coded to $0$, meaning that the liquidity decrease operation will accept **ANY** amount in exchange, even $0$, leading to a loss of funds as MEV exists in Solana too (see [here](https://explorer.jito.wtf/)). The mathematical reason is that

$$x >= 0, \forall x \in [0, 2⁶⁴-1]$$

so the errors

```rs
    if delta_a < token_min_a {
        return Err(ErrorCode::TokenMinSubceeded.into());
    } else if delta_b < token_min_b {
        return Err(ErrorCode::TokenMinSubceeded.into());
    }
```

won't be triggered as

```rs
    if delta_a < token_min_a { // @audit delta_a < 0 => false for all delta_a, so no error
        return Err(ErrorCode::TokenMinSubceeded.into());
    } else if delta_b < token_min_b { // @audit delta_b < 0 => false for al delta_b, so no error
        return Err(ErrorCode::TokenMinSubceeded.into());
    }

    // @audit if token_min_a = token_min_b = 0, then delta_a and delta_b can be ANY value, 
    // @audit even 0, w
drained funds are not correctly accounted in the treasury and cannot be withdrawn
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Treasury.sol#L482


# Vulnerability details

When native token (ETH) is passed to the treasury its value is accounted and also checked to no overflow the uin96 maximal value. This is done so the contract owner can withdraw the ETH token.

## Impact

Drained funds from the service registry are lost.

## Proof of Concept

The draining happens here:

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Treasury.sol#L482

The `ETHOwned` state variable is used to track ETH inflow to the treasury contract.
But when draining the slashed funds from the service strategy the transferred ETH is not accounted (`ETHOwned` is unchanged) like is done in other methods receiving the native token.

When the Treasury contract owner withdraws native token it can only withdraw to the `ETHOwned` amount:

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Treasury.sol#L331-L333

## Tools Used
Manual review

## Recommended Mitigation Steps

Account for ETH when draining funds from the service strategy :

```diff
    function drainServiceSlashedFunds() external returns (uint256 amount) {
        // Check for the contract ownership
        if (msg.sender != owner) {
            revert OwnerOnly(msg.sender, owner);
        }


        // Get the service registry contract address
        address serviceRegistry = ITokenomics(tokenomics).serviceRegistry();


        // Check if the amount of slashed funds are at least the minimum required amount to receive by the Treasury
        uint256 slashedFunds = IServiceRegistry(serviceRegistry).slashedFunds();
        if (slashedFunds < minAcceptedETH) {
            revert LowerThan(slashedFunds, minAcceptedETH);
        }


        // Call the service registry drain function
        amount = IServiceRegistry(serviceRegistry).drain();
+
+       uint256 newAmount = ETHOwned;
+       newAmount += amount;
+       if (newAmount + ETHFromServices > type(uint96).max) {
+           revert Overflow(newAmount, type(uint96).max);
+       }
+
+       ETHOwned = uint96(newAmount);
+       emit ReceiveETH(serviceRegistry, amount);
+   }
```


## Assessed type

ETH-Transfer
'IServiceRegistry' defines methods that the real ServiceRegistry does not implement
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/interfaces/IServiceRegistry.sol#L21-L22


# Vulnerability details

There are three methods missing. One is just a view but is used when tracking donations and will cause a revert when called.
The other two are used together when draining slashed founds to the treasury.
In the provided tests a mock contract which has this methods implemented is used so there are no reverts happening.

## Impact

Becouse the missing methods depositing donation to services which is an important part of the protocol will not work.
Also draining slashed funds is hampered becouse the same reason.

## Proof of Concept

The missing methods are:

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/interfaces/IServiceRegistry.sol#L21-L22

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/interfaces/IServiceRegistry.sol#L30

and

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/interfaces/IServiceRegistry.sol#L26C14-L26C26

They are used in tracking donations:

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Tokenomics.sol#L716-L717

and in draining funds to the treasury:

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Treasury.sol#L476
https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Treasury.sol#L482

The mock does implement them:

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/test/MockRegistry.sol#L36
https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/test/MockRegistry.sol#L78
https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/test/MockRegistry.sol#L84

The real contract does not implement them.

## Tools Used
Manual review

## Recommended Mitigation Steps

Implement the two mentioned methods inside the real contract.


## Assessed type

Error
Multiple solidity versions in one project, may cause compatibility and security issues
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/main/governance/contracts/OLAS.sol#L1-L6
https://github.com/code-423n4/2023-12-autonolas/blob/main/governance/contracts/GovernorOLAS.sol#L1-L2
https://github.com/code-423n4/2023-12-autonolas/blob/main/governance/contracts/wveOLAS.sol#L1-L2
https://github.com/code-423n4/2023-12-autonolas/blob/main/governance/contracts/bridges/BridgedERC20.sol#L1-L2


# Vulnerability details

## Impact
Multiple different Solidity versions ( ^0.8.15, ^0.8.19, ^0.8.20 , ^0.8.23 )  may affect the security and compatibility of the entire project

## Proof of Concept

In governance , there are multiple solidity used .

Olas.sol
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.15;
```

wveOLAS.sol
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
```

GovernorOLAS.sol
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
```

BridgedERC20.sol
```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.23;

```

## Tools Used
Manual Review

## Recommended Mitigation Steps
Unify all Solidity contract versions , for example ` ^0.8.19`


## Assessed type

Other
Protocol assumes that LP price is fixed when bonding in Depository.sol
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/tokenomics/contracts/Depository.sol#L183


# Vulnerability details

## Proof of Concept

In Depository.sol, users can deposit their LP tokens in exchange for OLAS tokens using the `deposit()` function. The OLAS tokens can only be redeemed using `redeem()` a day after the LP tokens is deposited. This mechanism is known as a bond.

One side of the LP token is always OLAS. OLAS will be paired with more common tokens like WETH and DAI.

Before users can deposit their LP tokens, the owner will first have to create the bond product using `create()`

```
    function create(address token, uint256 priceLP, uint256 supply, uint256 vesting) external returns (uint256 productId) {
```

Here, the owner sets the price of the LP, the vesting duration, and the total amount of OLAS supply to be exchanged. 

The exchange rate of LP tokens and OLAS tokens is calculated through the GenericBondCalculator.sol contract. 

```
  function calculatePayoutOLAS(uint256 tokenAmount, uint256 priceLP) external view
        returns (uint256 amountOLAS)
    {

 uint256 totalTokenValue = mulDiv(priceLP, tokenAmount, 1);
        // Check for the cumulative LP tokens value limit
        if (totalTokenValue > type(uint192).max) {
            revert Overflow(totalTokenValue, type(uint192).max);
        }
        // Amount with the discount factor is IDF * priceLP * tokenAmount / 1e36
        // At this point of time IDF is bound by the max of uint64, and totalTokenValue is no bigger than the max of uint192
        amountOLAS = ITokenomics(tokenomics).getLastIDF() * totalTokenValue / 1e36;
    }
```

For simplicity sake, let's assume that 1 OLAS-ETH LP token costs 1000 USD and after the calculation, it can be exchanged for 100 OLAS tokens.

This bond exchange rate is assumed to be a good starting point for the protocol.

However, after some time, the LP token decreases in price. LP tokens will decrease in price when the either of the token in the token pair drops in value. It is worse when both tokens are non-stable, eg OLAS-ETH.

If ETH drops drastically in price, then 1 OLAS-ETH is now worth 500 USD. Since priceLP is fixed, users can get 2 OLAS-ETH LP token and exchange for 200 OLAS tokens, with just 1000 USD.

https://dailydefi.org/articles/lp-token-value-calculation/

```
function calculatePayoutOLAS(uint256 tokenAmount, uint256 priceLP) external view
     // priceLP is fixed
     // tokenAmount depends on how much LP the user deposits
     uint256 totalTokenValue = mulDiv(priceLP, tokenAmount, 1)
```

This will create an unfair advantage for the users, at the expense of the protocol.

## Impact

If the LP price decreases, users will get more OLAS than intended.

## Tools Used

VS Code

## Recommended Mitigation Steps

Recommend protocol not fixing the LP price. Instead, use a TWAP or the "Fair LP Pricing" Formula by Alpha Homura (although that would require protocol to u
Risk of Sandwich Trading During Liquidity Withdrawal from Orca
Audit: 2023-12-autonolas-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-12-autonolas/blob/2a095eb1f8359be349d23af67089795fb0be4ed1/lockbox-solana/solidity/liquidity_lockbox.sol#L277


# Vulnerability details

## Impact
Users can suffer losses due to MEV when withdrawing liquidity.

## Proof of Concept
On Solana, a validator chosen by the Leader Rotation Mechanism can arbitrarily order transactions. This mechanism can lead to significant user losses if the minimum output for each token is not checked when burning LP Tokens and withdrawing liquidity.

```solidity
function withdraw(uint64 amount) external {
     ...
     whirlpool.decreaseLiquidity{accounts: metasDecreaseLiquidity, seeds: [[pdaProgramSeed, pdaBump]]}(amount, 0, 0);
    ...
}
```



## Tools Used
Manual Audit

## Recommended Mitigation Steps
Referring to the Orca whirlpool code (https://github.com/orca-so/whirlpools/blob/fc7dac3037c208fd1806ec80b8a43fbcc6648bdc/programs/whirlpool/src/lib.rs#L251-L256), it is advisable to set the second and third arguments of decrease_liquidity to something other than zero. These should be parameters additionally received through the withdraw function.


## Assessed type

MEV
Complete WithdrawalRequest denial of service by manipulating expiry via malicious calldata struct encoding
Audit: 2024-03-coinbase-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-03-coinbase/blob/e0573369b865d47fed778de00a7b6df65ab1744e/src/MagicSpend/MagicSpend.sol#L114


# Vulnerability details

## Impact
Maliciously constructed WithdrawRequest calldata structs (for example reordered or constructed by bad frontend) can manipulate `expiry` value decoding to DOS all MagicSpend WithdrawRequests from a signer.

Manually restructured WithdrawRequest calldata (using nonstandard ABI encoding) which is formatted to fit a EIP2098 compact signature can derive and then pack a full 65 byte signature into the same struct without altering its hash. This is achieved by using the big endian side of the `expiry` slot to store the `uint8 v` yParity and arises due to malleability of ABI encoding as well as MagicSpend's lack of enforcement and validation for the struct's encoding. 

Since a full 65 byte signature can be obtained from a compact EIP2098 (and vice versa), malicious dapps need only present such nonstandard WithdrawRequests for unsuspecting users to sign, effectively granting dapps the right to deny UserOperations containing WithdrawRequests in the `paymasterAndData` field. When structured as shown in the PoC, `expiry` is tricked to return the length of the signature (64 or 65) as opposed to a relevant `block.timestamp` in Unix format. This means the signature expired in 1972 and is completely unusable.

## Proof of Concept
The following test file is designed for integration with the audit repository by being placed in a new "PoC" or other name dir within `2024-03-coinbase/test/SmartWallet/` and then run to observe the attack:

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Test, console2} from "forge-std/Test.sol";
import {SignatureCheckerLib} from "solady/utils/SignatureCheckerLib.sol";
import {UserOperation, UserOperationLib} from "account-abstraction/interfaces/UserOperation.sol";
import {IStakeManager} from "account-abstraction/interfaces/IStakeManager.sol";
import {calldataKeccak} from "account-abstraction/core/Helpers.sol";
import {MockEntryPoint} from "../mocks/MockEntryPoint.sol";
import "test/MagicSpend/PaymasterMagicSpendBase.sol";
import "../CoinbaseSmartWallet/SmartWalletTestBase.sol";

contract PoC is Test {
    /// forge-config: default.fuzz.runs = 10_000_000

    // dummy event for lazy selector encoding
    event UserOperationEvent(bytes32 indexed userOpHash, address indexed sender, address indexed paymaster, uint256 nonce, bool success, uint256 actualGasCost, uint256 actualGasUsed);

    uint256 msOwnerPrivateKey = 0xdeadbeef;
    address msOwner = vm.addr(msOwnerPrivateKey);
    MagicSpend magicSpend = new MagicSpend(msOwner);
    CoinbaseSmartWallet account = new MockCoinbaseSmartWallet();
    CoinbaseSmartWallet validUserAccount = new MockCoinbaseSmartWallet();
    IEntryPoint entryPoint = IEntryPoint(0x5FF137D4b0FDCD49DcA30c7CF57E578a026d2789);

    // userop signature params
    uint256 signerPrivateKey = 0xa11ce;
    addres