Cairo settlement contract does not check if the cross-chain message was already received on `receive_cross_chain_msg` which allows malicious users to drain the protocol funds
Audit: 2024-08-chakra-findings
Severity: HIGH

# Lines of code

https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/settlement.cairo#L325-L383


# Vulnerability details

## Impact
When a cross-chain message is received on the settlement contract on Starknet, `receive_cross_chain_msg` is triggered by one of the validators after the signatures are signed to process the message. The settlement contract [interacts with the handler contract](https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/settlement.cairo#L354) to process the ERC20 transfer, [either minting or unlocking](https://github.com/code-423n4/2024-08-chakra/blob/abef77d95866f2fec93270491fc5abc9ab14f86d/cairo/handler/src/handler_erc20.cairo#L125-L132) the tokens to the recipient
```rs
fn receive_cross_chain_msg(
    ref self: ContractState,
    cross_chain_msg_id: u256,
    from_chain: felt252,
    to_chain: felt252, 
    from_handler: u256,
    to_handler: ContractAddress,
    sign_type: u8,
    signatures: Array<(felt252, felt252, bool)>,
    payload: Array<u8>,
    payload_type: u8,
) -> bool {
    assert(to_chain == self.chain_name.read(), "error to_chain");

    // verify signatures
    let mut message_hash: felt252 = LegacyHash::hash(from_chain, (cross_chain_msg_id, to_chain, from_handler, to_handler));
    let payload_span = payload.span();
    let mut i = 0;
    loop {
        if i > payload_span.len()-1{
            break;
        }
        message_hash = LegacyHash::hash(message_hash, * payload_span.at(i));
        i += 1;
    };
    self.check_chakra_signatures(message_hash, signatures); 
            
>>>    // @audit No check if the message was received already    
        
    // call handler receive_cross_chain_msg
    let handler = IHandlerDispatcher{contract_address: to_handler};
    let success = handler.receive_cross_chain_msg(cross_chain_msg_id, from_chain, to_chain, from_handler, to_handler , payload);

    let mut status = CrossChainMsgStatus::SUCCESS;
    if success{
        status = CrossChainMsgStatus::SUCCESS;
    }else{
        status = CrossChainMsgStatus::FAILED;
    }

    // --SNIP
    return true;
}
```
The issue is that the function does not check whether the cross-chain message has already been received. As a result, a malicious actor can reuse the function arguments from the first transaction to repeatedly call the function, leading to a continuous unlocking or minting of tokens to the recipient. This could ultimately drain the protocol's funds.
## Tools Used
Manual Review

## Recommended Mitigation Steps
implement a check within `receive_cross_chain_msg` to ensure that the message has not already been received:
```diff
```rs
fn receive_cross_chain_msg(
    ref self: ContractState,
    cross_chain_msg_id: u256,
    from_chain: felt252,
    to_chain: felt252, 
    from_handler: u256,
    to_handler: ContractAddress,
    sign_type: u8,
    signatures: Array<(felt252, felt252, bool)>,
    paylo