Vulnerability: When private keeper mode is off users can queue orders with the wrong asset
Severity: high

Description:
After an order is initiated, it must be filled by calling resolveQueuedTrades. This function validates that the asset price has been signed but never validates that the asset being passed in matches the asset of the queuedTrade. When private keeper mode is off, which is the default state of the contract, this can be abused to cause huge loss of funds.\\n```\\n    for (uint32 index = 0; index < params.length; index++) {\\n        OpenTradeParams memory currentParams = params[index];\\n        QueuedTrade memory queuedTrade = queuedTrades[\\n            currentParams.queueId\\n        ];\\n        bool isSignerVerifed = _validateSigner(\\n            currentParams.timestamp,\\n            currentParams.asset,\\n            currentParams.price,\\n            currentParams.signature\\n        );\\n        // Silently fail if the signature doesn't match\\n        if (!isSignerVerifed) {\\n            emit FailResolve(\\n                currentParams.queueId,\\n                "Router: Signature didn't match"\\n            );\\n            continue;\\n        }\\n        if (\\n            !queuedTrade.isQueued ||\\n            currentParams.timestamp != queuedTrade.queuedTime\\n        ) {\\n            // Trade has already been opened or cancelled or the timestamp is wrong.\\n            // So ignore this trade.\\n            continue;\\n        }\\n\\n        // If the opening time is much greater than the queue time then cancel the trad\\n        if (block.timestamp - queuedTrade.queuedTime <= MAX_WAIT_TIME) {\\n            _openQueuedTrade(currentParams.queueId, currentParams.price);\\n        } else {\\n            _cancelQueuedTrade(currentParams.queueId);\\n            emit CancelTrade(\\n                queuedTrade.user,\\n                currentParams.queueId,\\n                "Wait time too high"\\n            );\\n        }\\n\\n        // Track the next queueIndex to be processed for user\\n        userNextQueueIndexToProcess[queuedTrade.user] =\\n            queuedTrade.userQueueIndex +\\n            1;\\n    }\\n```\\n\\nBufferRouter#resolveQueueTrades never validates that the asset passed in for params is the same asset as the queuedTrade. It only validates that the price is the same, then passes the price and queueId to _openQueuedTrade:\\n```\\nfunction _openQueuedTrade(uint256 queueId, uint256 price) internal {\\n    QueuedTrade storage queuedTrade = queuedTrades[queueId];\\n    IBufferBinaryOptions optionsContract = IBufferBinaryOptions(\\n        queuedTrade.targetContract\\n    );\\n\\n    bool isSlippageWithinRange = optionsContract.isStrikeValid(\\n        queuedTrade.slippage,\\n        price,\\n        queuedTrade.expectedStrike\\n    );\\n\\n    if (!isSlippageWithinRange) {\\n        _cancelQueuedTrade(queueId);\\n        emit CancelTrade(\\n            queuedTrade.user,\\n            queueId,\\n            "Slippage limit exceeds"\\n        );\\n\\n        return;\\n    }\\n\\n    // rest of code\\n\\n    optionParams.totalFee = revisedFee;\\n    optionParams.strike = price;\\n    optionParams.amount = amount;\\n\\n    uint256 optionId = optionsContract.createFromRouter(\\n        optionParams,\\n        isReferralValid\\n    );\\n```\\n\\nInside _openQueuedTrade it checks that the price is within the slippage bounds of the order, cancelling if its not. Otherwise it uses the price to open an option. According to documentation, the same router will be used across a large number of assets/pools, which means the publisher for every asset is the same, given that router only has one publisher variable.\\nExamples:\\nImagine two assets are listed that have close prices, asset A = $0.95 and asset B = $1. An adversary could create an call that expires in 10 minutes on asset B with 5% slippage, then immediately queue it with the price of asset A. $0.95 is within the slippage bounds so it creates the option with a strike price of $0.95. Since the price of asset B is actually $1 the adversary will almost guaranteed make money, stealing funds from the LPs. This can be done back and forth between both pools until pools for both assets are drained.\\nIn a similar scenario, if the price of the assets are very different, the adversary could use this to DOS another user by always calling queue with the wrong asset, causing the order to be cancelled.

Impact:
Adversary can rug LPs and DOS other users

Recommended mitigation:
Pass the asset address through so the BufferBinaryOptions contract can validate it is being called with the correct asset