TempleGold

TempleDAO
Foundry
25,000 USDC
View results
Submission Details
Severity: high
Valid

Potential Blocking of Cross-Chain Transfers for MultiSig and Account Abstraction Wallets in `TempleGold.sol`

Summary

The TempleGold.sol contract aims to restrict cross-chain transfers to self-transfers only by ensuring that the sender and recipient addresses are the same. However, this restriction may prevent users of multi-signature wallets or account abstraction wallets, which can have different addresses on different chains, from performing legitimate cross-chain transfers to themselves.

Vulnerability Details

The relevant function in TempleGold.sol is as follows:

function send(
SendParam calldata _sendParam,
MessagingFee calldata _fee,
address _refundAddress
) external payable virtual override(IOFT, OFTCore) returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) {
if (_sendParam.composeMsg.length > 0) { revert CannotCompose(); }
/// cast bytes32 to address
address _to = _sendParam.to.bytes32ToAddress();
/// @dev user can cross-chain transfer to self
if (msg.sender != _to) { revert ITempleGold.NonTransferrable(msg.sender, _to); }
// @dev Applies the token transfers regarding this send() operation.
(uint256 amountSentLD, uint256 amountReceivedLD) = _debit(
msg.sender,
_sendParam.amountLD,
_sendParam.minAmountLD,
_sendParam.dstEid
);
// @dev Builds the options and OFT message to quote in the endpoint.
(bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD);
// @dev Sends the message to the LayerZero endpoint and returns the LayerZero msg receipt.
msgReceipt = _lzSend(_sendParam.dstEid, message, options, _fee, _refundAddress);
// @dev Formulate the OFT receipt.
oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD);
emit OFTSent(msgReceipt.guid, _sendParam.dstEid, msg.sender, amountSentLD, amountReceivedLD);
}

The check if (msg.sender != _to) { revert ITempleGold.NonTransferrable(msg.sender, _to); } ensures that users can only send tokens to themselves. This is generally good for maintaining non-transferability, but it can cause issues in certain scenarios:

  1. MultiSig Wallets: Multi-signature wallets may have different addresses on different chains, making it impossible for the wallet to transfer tokens to itself across chains.

  2. Account Abstraction Wallets: With account abstraction, wallets may be deployed with different addresses on different chains, especially if the deployment logic or parameters change.

Impact

  1. Blocking Legitimate Transfers: Users with multi-signature or account abstraction wallets might be unable to transfer their tokens cross-chain to themselves.

  2. Loss of Tokens: If users inadvertently send tokens to an address they don't control on the destination chain, it could lead to loss of tokens, especially if the address is controlled by someone else.

Proof of Concept (PoC)

Consider a scenario where a multi-signature wallet MultiSigA on Chain A has a different address MultiSigB on Chain B due to the deployment logic.

  1. User initiates a transfer from MultiSigA on Chain A to MultiSigB on Chain B.

  2. The contract will revert the transaction because msg.sender (which is MultiSigA) is not equal to _to (which is MultiSigB).

Recommendations

  1. Optional Validation for Specific Wallet Types: Implement an optional validation mechanism that allows multi-signature and account abstraction wallets to specify their corresponding addresses on the destination chain.

  2. User-Defined Address Mapping: Allow users to define and map their corresponding addresses on different chains. This could be implemented through a registration mechanism where users register their cross-chain addresses.

mapping(address => address) public crossChainAddressMapping;
function registerCrossChainAddress(address destinationAddress) external {
crossChainAddressMapping[msg.sender] = destinationAddress;
}
function send(
SendParam calldata _sendParam,
MessagingFee calldata _fee,
address _refundAddress
) external payable virtual override(IOFT, OFTCore) returns (MessagingReceipt memory msgReceipt, OFTReceipt memory oftReceipt) {
if (_sendParam.composeMsg.length > 0) { revert CannotCompose(); }
address _to = _sendParam.to.bytes32ToAddress();
// Check if the sender has registered a cross-chain address
address registeredAddress = crossChainAddressMapping[msg.sender];
if (msg.sender != _to && (registeredAddress == address(0) || registeredAddress != _to)) {
revert ITempleGold.NonTransferrable(msg.sender, _to);
}
// Token transfer logic remains the same
(uint256 amountSentLD, uint256 amountReceivedLD) = _debit(msg.sender, _sendParam.amountLD, _sendParam.minAmountLD, _sendParam.dstEid);
(bytes memory message, bytes memory options) = _buildMsgAndOptions(_sendParam, amountReceivedLD);
msgReceipt = _lzSend(_sendParam.dstEid, message, options, _fee, _refundAddress);
oftReceipt = OFTReceipt(amountSentLD, amountReceivedLD);
emit OFTSent(msgReceipt.guid, _sendParam.dstEid, msg.sender, amountSentLD, amountReceivedLD);
}

This solution provides flexibility for users with multi-signature or account abstraction wallets, ensuring they can perform legitimate cross-chain transfers while maintaining the non-transferability of TempleGold tokens.

Updates

Lead Judging Commences

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

Account abstraction, Multisig, Any other contract based solution that doesn't share the same address across chains will lose it's TGLD in teleport.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.