MultiInvoker closableAmount the calculation logic is wrong
in `MultiInvoker._latest()` The incorrect use of `previousMagnitude = latestPosition.magnitude()` has led to an error in the calculation of `closableAmount`. This has caused errors in judgments that use this variable, such as `_liquidationFee()`.\\nThere are currently multiple places where the user's `closable` needs to be calculated, such as `market.update()`. The calculation formula is as follows in the code: `Market.sol`\\n```\\n    function _processPendingPosition(Context memory context, Position memory newPendingPosition) private {\\n        context.pendingCollateral = context.pendingCollateral\\n            .sub(newPendingPosition.fee)\\n            .sub(Fixed6Lib.from(newPendingPosition.keeper));\\n          \\n        context.closable = context.closable\\n            .sub(context.previousPendingMagnitude\\n                .sub(newPendingPosition.magnitude().min(context.previousPendingMagnitude)));\\n      context.previousPendingMagnitude = newPendingPosition.magnitude();\\n\\n        if (context.previousPendingMagnitude.gt(context.maxPendingMagnitude))\\n            context.maxPendingMagnitude = newPendingPosition.magnitude();\\n    }\\n```\\n\\nIt will loop through `pendingPostion`, and each loop will set the variable `context.previousPendingMagnitude = newPendingPosition.magnitude();` to be used as the basis for the calculation of the next `pendingPostion`.\\n`closableAmount` is also calculated in `MultiInvoker._latest()`. The current implementation is as follows:\\n```\\n    function _latest(\\n        IMarket market,\\n        address account\\n    ) internal view returns (Position memory latestPosition, Fixed6 latestPrice, UFixed6 closableAmount) {\\n        // load latest price\\n        OracleVersion memory latestOracleVersion = market.oracle().latest();\\n        latestPrice = latestOracleVersion.price;\\n        IPayoffProvider payoff = market.payoff();\\n        if (address(payoff) != address(0)) latestPrice = payoff.payoff(latestPrice);\\n\\n        // load latest settled position\\n        uint256 latestTimestamp = latestOracleVersion.timestamp;\\n        latestPosition = market.positions(account);\\n        closableAmount = latestPosition.magnitude();\\n        UFixed6 previousMagnitude = closableAmount;\\n\\n        // scan pending position for any ready-to-be-settled positions\\n        Local memory local = market.locals(account);\\n        for (uint256 id = local.latestId + 1; id <= local.currentId; id++) {\\n\\n            // load pending position\\n            Position memory pendingPosition = market.pendingPositions(account, id);\\n            pendingPosition.adjust(latestPosition);\\n\\n            // virtual settlement\\n            if (pendingPosition.timestamp <= latestTimestamp) {\\n                if (!market.oracle().at(pendingPosition.timestamp).valid) latestPosition.invalidate(pendingPosition);\\n                latestPosition.update(pendingPosition);\\n\\n                previousMagnitude = latestPosition.magnitude();\\n                closableAmount = previousMagnitude;\\n\\n            // process pending positions\\n            } else {\\n                closableAmount = closableAmount\\n                    .sub(previousMagnitude.sub(pendingPosition.magnitude().min(previousMagnitude)));\\n              previousMagnitude = latestPosition.magnitude();\\n            }\\n        }\\n    }\\n```\\n\\nThis method also loops through `pendingPosition`, but incorrectly uses `latestPosition.magnitude()` to set `previousMagnitude`, `previousMagnitude` = latestPosition.magnitude();. The correct way should be `previousMagnitude = currentPendingPosition.magnitude()` like `market.sol`. This mistake leads to an incorrect calculation of `closableAmount`.
```\\n    function _latest(\\n        IMarket market,\\n        address account\\n    ) internal view returns (Position memory latestPosition, Fixed6 latestPrice, UFixed6 closableAmount) {\\n        // load latest price\\n        OracleVersion memory latestOracleVersion = market.oracle().latest();\\n        latestPrice = latestOracleVersion.price;\\n        IPayoffProvider payoff = market.payoff();\\n        if (address(payoff) != address(0)) latestPrice = payoff.payoff(latestPrice);\\n\\n        // load latest settled position\\n        uint256 latestTimestamp = latestOracleVersion.timestamp;\\n        latestPosition = market.positions(account);\\n        closableAmount = latestPosition.magnitude();\\n        UFixed6 previousMagnitude = closableAmount;\\n\\n        // scan pending position for any ready// Remove the line below\\nto// Remove the line below\\nbe// Remove the line below\\nsettled positions\\n        Local memory local = market.locals(account);\\n        for (uint256 id = local.latestId // Add the line below\\n 1; id <= local.currentId; id// Add the line below\\n// Add the line below\\n) {\\n\\n            // load pending position\\n            Position memory pendingPosition = market.pendingPositions(account, id);\\n            pendingPosition.adjust(latestPosition);\\n\\n            // virtual settlement\\n            if (pendingPosition.timestamp <= latestTimestamp) {\\n                if (!market.oracle().at(pendingPosition.timestamp).valid) latestPosition.invalidate(pendingPosition);\\n                latestPosition.update(pendingPosition);\\n\\n                previousMagnitude = latestPosition.magnitude();\\n                closableAmount = previousMagnitude;\\n\\n            // process pending positions\\n            } else {\\n                closableAmount = closableAmount\\n                    .sub(previousMagnitude.sub(pendingPosition.magnitude().min(previousMagnitude)));\\n// Remove the line below\\n               previousMagnitude = latestPosition.magnitude();\\n// Add the line below\\n               previousMagnitude = pendingPosition.magnitude();\\n            }\\n        }\\n    }\\n```\\n
The calculation of `closableAmount` is incorrect, which leads to errors in the judgments that use this variable, such as `_liquidationFee()`.
```\\n    function _processPendingPosition(Context memory context, Position memory newPendingPosition) private {\\n        context.pendingCollateral = context.pendingCollateral\\n            .sub(newPendingPosition.fee)\\n            .sub(Fixed6Lib.from(newPendingPosition.keeper));\\n          \\n        context.closable = context.closable\\n            .sub(context.previousPendingMagnitude\\n                .sub(newPendingPosition.magnitude().min(context.previousPendingMagnitude)));\\n      context.previousPendingMagnitude = newPendingPosition.magnitude();\\n\\n        if (context.previousPendingMagnitude.gt(context.maxPendingMagnitude))\\n            context.maxPendingMagnitude = newPendingPosition.magnitude();\\n    }\\n```\\n