Users can lost their USDY tokens in the Source Chain if something fails during the crosschain communication because there is not a validation mechanism to confirm that tokens were minted in the Destination Chain
Audit: 2023-09-ondo-findings
Severity: MEDIUM

# Lines of code

https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/SourceBridge.sol#L61-L82


# Vulnerability details

## Impact
- Users can lost their USDY tokens that were burnt in the Source Chain when bridging to another chain.

## Proof of Concept
- The bridging implementation solely relies and assumes that all messages sent to the Axelar Network will be validated and won't have any problems to be posted on the Destination Chain, the existing logic [burns tokens on the Source Chain and sends the message to the Axelar Network through the Axelar Gateway that is deployed on the Source Chain](https://github.com/code-423n4/2023-09-ondo/blob/main/contracts/bridge/SourceBridge.sol#L61-L82), the Axelar Gateway only emits an event to confirm that it received the message.
  - From this point and beyond, the DestinationBridge must wait until the Axelar Network receives and process the message sent from the Source Chain into the Destination Chain.
`burnAndCallAxelar() => _payGasAndCallContract() => AXELAR_GATEWAY.callContract()`
    - The [`AXELAR_GATEWAY.callContract()`](https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/AxelarGateway.sol#L151-L164) function only emits an event!
```solidity
function burnAndCallAxelar(
  uint256 amount,
  string calldata destinationChain
) external payable whenNotPaused {
  // check destinationChain is correct
  string memory destContract = destChainToContractAddr[destinationChain];

  if (bytes(destContract).length == 0) {
    revert DestinationNotSupported();
  }

  if (msg.value == 0) {
    revert GasFeeTooLow();
  }
  
  //@audit-info => Burns tokens on the Source Chain
  // burn amount
  TOKEN.burnFrom(msg.sender, amount);

  bytes memory payload = abi.encode(VERSION, msg.sender, amount, nonce++);

  //@audit-info => Will send the message to mint tokens on the Destination Chain by using the Axelar Network
  _payGasAndCallContract(destinationChain, destContract, payload);
}


function callContract(
    string calldata destinationChain,
    string calldata destinationContractAddress,
    bytes calldata payload
) external {
  //@audit-info => The Axelar Gateway only emits an event!
    emit ContractCall(msg.sender, destinationChain, destinationContractAddress, keccak256(payload), payload);
}
```

- To execute the minting of the tokens in the Destination Chain, the DestinationBridge calls the [Axelar Network to verify if the call sent from the sourceChain has already been processed](https://github.com/axelarnetwork/axelar-cgp-solidity/blob/main/contracts/AxelarGateway.sol#L232-L250), and **if the message hasn't been posted on the DestinationChain, the tx is reverted**
```solidity
function execute(
  bytes32 commandId,
  string calldata sourceChain,
  string calldata sourceAddress,
  bytes calldata payload
) external {
  bytes32 payloadHash = keccak256(payload);

  //@audit-info => If tx is not approved in the axelar gateway in the Destination Chain, the tx will be reverted.
  i