作者：[@Ethan](https://x.com/SnowS39053)

---

# getAllPools 方法可能出现数据覆盖

## 漏洞说明

漏洞在代码 [PoolManager.sol#L36](https://github.com/WTFAcademy/WTF-Dapp/blob/main/demo-contract/contracts/wtfswap/PoolManager.sol#L36) 处。

```solidity
poolsInfo = new PoolInfo[](length);
for (uint32 i = 0; i < pairs.length; i++) {
    address[] memory addresses = pools[pairs[i].token0][
        pairs[i].token1
    ];
    for (uint32 j = 0; j < addresses.length; j++) {
        IPool pool = IPool(addresses[j]);
        poolsInfo[i + j] = PoolInfo({
            pool: addresses[j],
            token0: pool.token0(),
            token1: pool.token1(),
            index: j,
            fee: pool.fee(),
            feeProtocol: 0,
            tickLower: pool.tickLower(),
            tickUpper: pool.tickUpper(),
            tick: pool.tick(),
            sqrtPriceX96: pool.sqrtPriceX96(),
            liquidity: pool.liquidity()
        });
    }
}
return poolsInfo;
```

当执行 `poolsInfo[i + j] = ...` 对数组进行赋值时, `i=2; j=0` 会将 `i=0;j=2` 时的数据覆盖

## 问题测试
部分测试函数如下:

```solidity
modifier poolCreated() {
        address pool1 = poolManager.createAndInitializePoolIfNecessary(params1);
        address pool2 = poolManager.createAndInitializePoolIfNecessary(params2);
        address pool3 = poolManager.createAndInitializePoolIfNecessary(params3);
        _;
    }

function comparePoolInfoWithParams(
    PoolManager.PoolInfo calldata poolInfo, 
    IPoolManager.CreateAndInitializeParams calldata params
) public pure returns(bool ok) {
    ok = poolInfo.token0 == params.token0 &&
        poolInfo.token1 == params.token1 &&
        poolInfo.fee == params.fee &&
        poolInfo.tickLower == params.tickLower &&
        poolInfo.tickUpper == params.tickUpper;
}

function testGetAllPools() public poolCreated {
    PoolManager.PoolInfo[] memory poolsInfo = poolManager.getAllPools();
    assertEq(poolsInfo.length, 3);

    IPoolManager.CreateAndInitializeParams[3] memory multiParams = [params1, params2, params3];
    console2.log(multiParams[0].token0, multiParams[1].token0, multiParams[2].token0);
    for (uint24 i=0; i < poolsInfo.length; i++) {
        assert(this.comparePoolInfoWithParams(poolsInfo[i], multiParams[i]));
    }
}
```
按照上述测试流程, 新建 pool 并通过 `getAllPools` 方法来获取 pool 信息, 与预期的参数进行比较, 将得到错误的比较结果

## 修复方法

两层 for 循环实际上已经获取了每个 pair 对应的 pool 数量, 只需要一个变量记录循环执行时的下标即可. 修复代码如下:

```diff
    poolsInfo = new PoolInfo[](length);
+   uint256 index;
    for (uint32 i = 0; i < pairs.length; i++) {
        address[] memory addresses = pools[pairs[i].token0][
            pairs[i].token1
        ];
        for (uint32 j = 0; j < addresses.length; j++) {
            IPool pool = IPool(addresses[j]);
-           poolsInfo[i + j] = PoolInfo({
+           poolsInfo[index] = PoolInfo({
                pool: addresses[j],
                token0: pool.token0(),
                token1: pool.token1(),
                index: j,
                fee: pool.fee(),
                feeProtocol: 0,
                tickLower: pool.tickLower(),
                tickUpper: pool.tickUpper(),
                tick: pool.tick(),
                sqrtPriceX96: pool.sqrtPriceX96(),
                liquidity: pool.liquidity()
            });
+           index++;
        }
    }
    return poolsInfo;
```
