# \[BIP-442\] Permissions Preset Update Request #2

**URL:** <https://forum.balancer.fi/t/bip-442-permissions-preset-update-request-2/5209>\
**Category:** Karpatkey Updates\
**Created:** [September 22, 2023, 1:48pm UTC](https://forum.balancer.fi/t/bip-442-permissions-preset-update-request-2/5209 "2023-09-22T13:48:01Z")\
**Posts on this page:** 1\
**Showing post:** 3

<div class="post-metadata">

**Author:** ![gosuto](https://yyz1.discourse-cdn.com/flex027/user_avatar/forum.balancer.fi/gosuto/32/2014_2.png) [@gosuto](https://forum.balancer.fi/u/gosuto)\
**Post date:** [October 11, 2023, 2:10pm UTC](https://forum.balancer.fi/t/bip-442-permissions-preset-update-request-2/5209/3 "2023-10-11T14:10:49Z")

</div>

# Due Dilligence: BIP-442 Karpatkey Payload

## Tenderly Simulation

> **[Tenderly Dashboard](https://dashboard.tenderly.co/public/safe/safe-apps/simulator/d884b97f-2bd6-4bcc-8242-84bbdfdf46c0/logs)**
>
> Tenderly is a full-stack infrastructure for the entire dapp lifecycle, offering the only node RPC with built-in development environments and tools. Sign up now!

## Interpreting Events

The payload can in this case be intepreted through the events it emits on a successful (simulated) execution. This is possible because the only functions that are called are approvals on ERC20s or scope changes on the [`Roles` module](https://etherscan.io/address/0xd8dd9164e765bef903e429c9462e51f0ea8514f9#code). All these functions emit relevant and exhaustive events.

### `Approval`

`Approval` events are pretty straight forward to interpret:

```json
{
    "owner": "0x0efccbb9e2c09ea29551879bd9da32362b32fc89"
    "spender": "0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0"
    "value": "115792089237316195423570985008687907853269984665640564039457584007913129639935"
}

```

The event is emitted from `0xae7ab96520de3a18e5e111b5eaab095312d7fe84`, which is stETH. On it, the [managed safe](https://app.safe.global/home?safe=eth:0x0EFcCBb9E2C09Ea29551879bd9Da32362b32fc89) (0x0efcc) approves the spender (wstETH) to spend infinite amount of tokens.

In all cases here, the owner is the managed safe and the amount of tokens is infinite. Mapping of tokens and spenders:

| token (symbol) | spender (label) |
| --- | --- |
| `0xae7ab96520de3a18e5e111b5eaab095312d7fe84` (stETH) | `0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0` (wstETH) |
| `0xae7ab96520de3a18e5e111b5eaab095312d7fe84` (stETH) | `0x889edc2edab5f40e902b864ad4d7ade8e412f9b1` (unstETH) |
| `0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0` (wstETH) | `0x889edc2edab5f40e902b864ad4d7ade8e412f9b1` (unstETH) |
| `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48` (USDC) | `0xc3d688b66703497daa19211eedff47f25384cdc3` (cUSDCv3) |
| `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48` (USDC) | `0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2` (Aave: Pool V3) |
| `0x6b175474e89094c44da98b954eedeac495271d0f` (DAI) | `0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2` (Aave: Pool V3) |
| `0xae78736cd615f374d3085123a210448e74fc6393` (rETH) | `0x16d5a408e807db8ef7c578279beeee6b228f1c1c` (RocketSwapRouter) |
| `0x6b175474e89094c44da98b954eedeac495271d0f` (DAI) | `0x373238337bfe1146fb49989fc222523f83081ddb` (DsrManager) |
| `0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9` (AAVE) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0xc00e94cb662c3520282e6f5717214004a7f26888` (COMP) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0x6b175474e89094c44da98b954eedeac495271d0f` (DAI) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0xae78736cd615f374d3085123a210448e74fc6393` (RETH) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0x20bc832ca081b91433ff6c17f85701b6e92486c5` (rETH2) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0xfe2e637202056d30016725477c5da089ab0a043a` (sETH2) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0x889edc2edab5f40e902b864ad4d7ade8e412f9b1` (unstETH) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0x48e5413b73add2434e47504e2a22d14940dbfe78` (INRM) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48` (USDC) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0xdac17f958d2ee523a2206206994597c13d831ec7` (USDT) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2` (WETH) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0x2260fac5e5542a773aa44fbcfedf7c193bc2c599` (WBTC) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |
| `0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0` (wstETH) | `0xc92e8bdf79f0507f65a392b0ab4667716bfe0110` (GPv2VaultRelayer; CoW Swap) |

**WARNING** : the approval of `0x48e5413b73add2434e47504e2a22d14940dbfe78` (INRM) seems unnecessary and is a bit puzzling to me. It is for example not whitelisted for the `CowswapOrderSigner.signOrder.sellToken` parameter (see `ScopeParameterAsOneOf` section). Is there something I am missing here, or is this a bug? How did this token get into this list?

### `ScopeFunction`

Besides the (more readable) approvals, this payload makes changes to the `Roles` module, which is currently enabled on the managed safe.

We can verify these permission changes made by checking the events emitted in the Tenderly simulation, e.g.:

```json
{
    "role": 1
    "targetAddress": "0x889edc2edab5f40e902b864ad4d7ade8e412f9b1"
    "functionSig": "0xd6681042"
    "isParamScoped": [
        0: false
        1: true
    ]
    "paramType": "AAA="
    "paramComp": "AAA="
    "compValue": [
        0: "0x"
        1: "0x0000000000000000000000000efccbb9e2c09ea29551879bd9da32362b32fc89"
    ]
    "options": 0
    "resultingScopeConfig": "3533694129556781213370065774847364703233814209084070120954101330654265344"
}

```

`role` here is the index of the `Role` struct, meaning in this case that there is a target type role change:

```solidity
struct Role {
    mapping(address => bool) members;
    mapping(address => TargetAddress) targets;
    mapping(bytes32 => uint256) functions;
    mapping(bytes32 => bytes32) compValues;
    mapping(bytes32 => bytes32[]) compValuesOneOf;
}

```

`target` and `functionSig` translate to the following:

```python
>>> target = Contract('0x889edc2edab5f40e902b864ad4d7ade8e412f9b1')
>>> target.name()
'Lido: stETH Withdrawal NFT'
>>> target.selectors['0xd6681042']
'requestWithdrawals'

```

This corresponds to point (5.) from karpatkey’s specs:

> 1. Unstake stETH on Lido;

The function’s full signature is `requestWithdrawals(uint256[] _amounts, address _owner)`, therefore:

- setting `isParamScoped` for the parameter with index `0` to `false` means any amount could be withdrawm, i.e. no limitation
- `isParamScoped` for the parameter for index `1` is set to `true` with value `0x0000000000000000000000000efccbb9e2c09ea29551879bd9da32362b32fc89`; the withdrawal can only take place to `0x0EFcCBb9E2C09Ea29551879bd9Da32362b32fc89` which is the managed treasury multisig address

`options` can give permission to send ether, use `delegate_call` or both:

```solidity
enum ExecutionOptions {
    None,
    Send,
    DelegateCall,
    Both
}

```

We can repeat this for all other scope type events emitted:

| contract | signature | scope |
| --- | --- | --- |
| `"Lido: stETH Withdrawal NFT"` | `requestWithdrawals(uint256[] _amounts, address _owner)` | ANY, 0x0efcc |
| `"Lido: stETH Withdrawal NFT"` | `requestWithdrawalsWstETH(uint256[] _amounts, address _owner)` | ANY, 0x0efcc |
| `"Aave: Pool V3"` | `supply(address asset, uint256 amount, address onBehalfOf)` | SCOPED\*, ANY, 0x0efcc |
| `"Aave: Pool V3"` | `withdraw(address asset, uint256 amount, address onBehalfOf)` | SCOPED\*, ANY, 0x0efcc |
| `"Compound USDC (cUSDCv3)"` | `supply(address asset, uint256 amount)` | USDC, ANY |
| `"Compound USDC (cUSDCv3)"` | `withdraw(address asset, uint256 amount)` | USDC, ANY |
| `"CometRewards"` | `claim(address comet, address src, bool shouldAccrue)` | cUSDCv3, 0x0efcc, ANY |
| `"DsrManager"` | `join(address dst, uint256 wad)` | 0x0efcc, ANY |
| `"DsrManager"` | `exitAll(address dst)` | 0x0efcc |
| `"RocketDepositPool"` | `deposit()` | SEND\_ETHER |
| `"Rocket Pool ETH"` | `burn(uint256 _rethAmount)` | ANY |
| `"RocketSwapRouter"` | `swapTo(uint256 _uniswapPortion, uint256 _balancerPortion, uint256 _minTokensOut, uint256 _idealTokensOut)` | ANY\*, SEND\_ETHER |
| `"RocketSwapRouter"` | `swapFrom(uint256 _uniswapPortion, uint256 _balancerPortion, uint256 _minTokensOut, uint256 _idealTokensOut, uint256 _tokensIn)` | ANY\* |
| `"CowswapOrderSigner"` | `signOrder(address sellToken, address buyToken, uint256 sellAmount, uint256 buyAmount, uint32 validTo, uint32 validDuration, uint256 feeAmount, uint256 feeAmountBP, bytes32 kind, bool partiallyFillable, bytes32 sellTokenBalance, bytes32 buyTokenBalance)` | SCOPED\*, SCOPED\*, ANY, ANY, ANY, ANY, ANY, ANY, ANY, ANY, ANY, ANY, SEND\_ETHER, DELEGATE\_CALL |

**WARNING** : deployer of `CowswapOrderSigner` does not look to be CoW DAO. Who deployed this contract?

**WARNING** : the `feeAmountBP` is not scoped, and can therefore be set to something like 99%. **There is a potential for malicious/griefing transactions here!**

### `ScopeParameterAsOneOf`

Some parameters do not get limited to a single value but to a list of values, as can be read from the `ScopeParameterAsOneOf` event:

```json
ScopeParameterAsOneOf{
    "role": 1
    "targetAddress": "0x87870bca3f3fd6335c3f4ce8392d69350b4fa4e2"
    "functionSig": "0x617ba037"
    "index": "0"
    "paramType": 0
    "compValues": [
        0: "0x0000000000000000000000006b175474e89094c44da98b954eedeac495271d0f"
        1: "0x000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48"
    ]
    "resultingScopeConfig":"5300541194335184374258569435632574726429567728958937386142040924050423811"
}

```

So the parameter with index `0` (`"Aave: Pool V3".supply.asset`) can have two values:

- `0x6b175474e89094c44da98b954eedeac495271d0f` (DAI)
- `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48` (USDC)

`"Aave: Pool V3".withdraw.asset` can be set to the same two addresses:

- `0x6b175474e89094c44da98b954eedeac495271d0f` (DAI)
- `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48` (USDC)

The `CowswapOrderSigner.signOrder.sellToken` parameter gets scoped to the following whitelist:

- `0x7fc66500c84a76ad7e9c93437bfc5ac33e2ddae9` (AAVE)
- `0xc00e94cb662c3520282e6f5717214004a7f26888` (COMP)
- `0x6b175474e89094c44da98b954eedeac495271d0f` (DAI)
- `0xae78736cd615f374d3085123a210448e74fc6393` (rETH)
- `0x20bc832ca081b91433ff6c17f85701b6e92486c5` (rETH2)
- `0xfe2e637202056d30016725477c5da089ab0a043a` (sETH2)
- `0xae7ab96520de3a18e5e111b5eaab095312d7fe84` (stETH)
- `0x48c3399719b582dd63eb5aadf12a40b4c3f52fa2` (SWISE)
- `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48` (USDC)
- `0xdac17f958d2ee523a2206206994597c13d831ec7` (USDT)
- `0x2260fac5e5542a773aa44fbcfedf7c193bc2c599` (WBTC)
- `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2` (WETH)
- `0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0` (wstETH)

And for `CowswapOrderSigner.signOrder.buyToken`:

- `0x6b175474e89094c44da98b954eedeac495271d0f` (DAI)
- `0xae78736cd615f374d3085123a210448e74fc6393` (rETH)
- `0xfe2e637202056d30016725477c5da089ab0a043a` (sETH2)
- `0xae7ab96520de3a18e5e111b5eaab095312d7fe84` (stETH)
- `0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48` (USDC)
- `0xdac17f958d2ee523a2206206994597c13d831ec7` (USDT)
- `0x2260fac5e5542a773aa44fbcfedf7c193bc2c599` (WBTC)
- `0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2` (WETH)
- `0x7f39c581f595b53c5cb19bd0b3f8da6c935e2ca0` (wstETH)

## Conclusion

The INRM token approval is puzzling but not necessarily a security issue.

For the CoW swap order signing however, I would recommend either (1) a scope on the `feeAmountBP` parameter or (2) a new (official) deployment of the signer contract which has a tighter sanity check on the fee ([ref](https://etherscan.io/address/0xdeb83d81d4a9758a7baec5749da863c409ea6c6b#code#F1#L79)) to prevent getting assets drained through unrealistic fees.

---

_[View the full topic](https://forum.balancer.fi/t/bip-442-permissions-preset-update-request-2/5209)._
