re-al-Foundation / rwa-contracts

0 stars 0 forks source link

[RRR-01M] Inexistent Graceful Handling of Cross-Chain Errors #55

Closed chasebrownn closed 6 months ago

chasebrownn commented 6 months ago

RRR-01M: Inexistent Graceful Handling of Cross-Chain Errors

Type Severity Location
Standard Conformity RealReceiver.sol:L169, L187, L205

Description:

All cross-chain messages relayed to the RealReceiver can fail due to the RWAToken reaching its maximum supply, however, none of the functions in the RealReceiver will gracefully handle such a case.

Impact:

The likelihood of the RWAToken achieving its maximum supply is an unlikely but possible scenario given that the state between RWAToken implementations is not necessarily in sync. In such a case, cross-chain relayed messages would result in loss of funds as the non-blocking LayerZero RealReceiver implementation would permit the failed transactions to be replayed but always fail.

Example:

/**
 * @notice Internal method for handling migration payloads for migrating to a veRWA NFT.
 * @param payload Payload containing NFT lock data.
 */
function _migrateNFT(bytes memory payload) internal {
    (, bytes memory toAddressBytes, uint256 amount, uint256 duration) =
        abi.decode(payload, (uint16, bytes, uint256, uint256));

    address to = toAddressBytes.toAddress(0);

    (bool success,) = address(veRwaNFT).call(
        abi.encodeWithSignature("migrate(address,uint256,uint256)", to, amount, duration)
    );
    if (!success) revert MigrationFailed(SEND_NFT);

    emit MigrationMessageReceived(SEND_NFT, to, payload);
}

/**
 * @notice Internal method for handling migration payloads for migrating a batch of veRWA NFTs.
 * @param payload Payload containing NFT lock data.
 */
function _migrateNFTBatch(bytes memory payload) internal {
    (, bytes memory toAddressBytes, uint256[] memory amounts, uint256[] memory durations) =
        abi.decode(payload, (uint16, bytes, uint256[], uint256[]));

    address to = toAddressBytes.toAddress(0);

    (bool success,) = address(veRwaNFT).call(
        abi.encodeWithSignature("migrateBatch(address,uint256[],uint256[])", to, amounts, durations)
    );
    if (!success) revert MigrationFailed(SEND_NFT_BATCH);

    emit MigrationMessageReceived(SEND_NFT_BATCH, to, payload);
}

/**
 * @notice Internal method for handling migration payloads for migrating to $RWA tokens.
 * @param payload Payload migration data.
 */
function _migrateTokens(bytes memory payload) internal {
    (, bytes memory toAddressBytes, uint256 amount) =
        abi.decode(payload, (uint16, bytes, uint256));

    address to = toAddressBytes.toAddress(0);

    (bool success,) = address(rwaToken).call(
        abi.encodeWithSignature("mintFor(address,uint256)", to, amount)
    );
    if (!success) revert MigrationFailed(SEND);

    emit MigrationMessageReceived(SEND, to, payload);
}

Recommendation:

We advise failure of the relevant migration functions to instead result in the message being relayed back to the origin chain, instructing the original contract to unlock / re-issue the funds it utilized as part of the migration process.

chasebrownn commented 6 months ago

This would never happen. RWA is migrated from TNGBL token, TNGBL token holder migrate 1-to-1 to RWA. And PINFT holders hold an NFT that represents TNGBL tokens that are already minted and accounted for so when it is migrated to veRWA NFT it will only mint RWA == TNGBL that was minted for the original NFT. TNGBL has the same maximum 33,333,333 supply and TNGBL minting is turned off at the moment.