Skip to content
$1,000,000 in security audit grants are live now, Apply here →

Security review · April 2025

Stable Wrappers

for USDT0

Guardian's review of Stable Wrappers for USDT0, published April 2025. The report records 6 findings, including 4 low and 2 informational.

Published
Review window
March 31 to April 2, 2025
Language
Solidity
Chains
Ethereum, Arbitrum, Ink, Hyperliquid, Polygon, Monad, Solana, Stellar
Sector
Stablecoins
  • 0 Critical
  • 0 High
  • 0 Medium
  • 4 Low
  • 2 Informational

6 acknowledged

Findings 6

  1. L-01 Low Absence Of quoteSend Implementation In OStableWrapper Code Best Practices Acknowledged
    Location
    OStableWrapper.sol

    Description

    The OStableWrapper contract provides a send function to facilitate cross‐chain transfers via LayerZero’s OFT. However, it does not implement a quoteSend (or equivalent) function to allow users or integrators to estimate fees or amounts prior to sending. Typically, LayerZero OFT contracts and wrappers expose quoteSend or a similar mechanism so that off‐chain services and dApps can easily query the bridging costs or token amounts in advance.

    Without quoteSend, developers or end users cannot directly compute how much native token or messaging fee they will need to attach to the send call and they would be forced to query the oft contract quoteSend function directly.

    Recommendation

    Add a quoteSend function at the OStableWrapper level that internally calls the OFT’s own quoting interface.

  2. L-02 Informational depositToAndCall is not EIP677 compatible Code Best Practices Acknowledged
    Location
    OStableWrapper.sol: 68

    Description

    According to EIP-677, the from argument of onTokenTransfer() should be the address which just transferred the tokens to the recipient. In the case of OStableWrapper.depositToAndCall(), that's the OStableWrapper itself, but the addressed passed to onTokenTransfer() is the msg.sender. This makes the wrapper not fully EIP677 compatible.

    Recommendation

    To make the wrapper EIP677 compatible, you can implement the following change:

    • return ITransferReceiver(recipient).onTokenTransfer(msg.sender, amountOut, data);
    • return ITransferReceiver(recipient).onTokenTransfer(address(this), amountOut, abi.encodePacked(msg.sender, data));
  3. L-03 Informational lzToken payments are not supported Warning Acknowledged
    Location
    OStableWrapper.sol

    Description

    OStableWrapper.send() accepts a MessagingFee parameter which may have lzTokenFee > 0. In this case, the OFT will try to pay with lz tokens by transferring them from the wrapper, but since it hasn't approved the OFT, the transaction will be reverting.

    Recommendation

    At the moment, the endpoint on the Stable chain hasn't enabled lzToken payments so it's enough to document the issue and keep in mind that a new wrapper has to be deployed in the future if the payment method is enabled and the team want to use it.

  4. L-04 Low Potential lzCompose Decoding Failure Warning Acknowledged
    Location
    StableComposer.sol

    Description

    The lzCompose function in the StableComposer contract expects the encoded compose message to include the recipient address. If the address is missing or incorrectly formatted, the call may fail during decoding, leaving the funds locked in the StableComposer contract.

    Recommendation

    Document this and consider implementing UI validations to ensure the correct format is used in the encoded compose message, preventing potential issues.

  5. L-05 Low lzCompose Token Lock Risk Warning Acknowledged
    Location
    StableComposer.sol

    Description

    The lzCompose function in the StableComposer contract is payable but calls the non-payable withdrawTo function as part of its logic. As a result, any native tokens sent to lzCompose effectively remain in the contract and are locked.

    Recommendation

    Add validation to ensure that msg.value is zero, or document this to make sure executors are aware that native tokens may be locked if sent to the contract.

  6. L-06 Low withdrawToWithPermit() can be blocked Warning Acknowledged
    Location
    OStableWrapper.sol: 91

    Description

    A malicious user can frontrun the call to OStableWrapper.withdrawToWithPermit() function with a direct call to token.permit(). This will make the permit() call in the OStableWrapper revert because the signature is already consumed. In result, withdrawals via withdrawToWithPermit() can be blocked.

    Recommendation

    Consider wrapping the permit call in a try/catch

More from USDT0

All 20 reports
  1. Stellar Deployment

    2 findings 2 findings: 2 informational
  2. Corn Network Delisting

    1 finding 1 finding: 1 low
  3. Canary Chain Configuration Verification

    4 findings 4 findings: 4 informational
  4. Solana Transaction Verification

    4 findings 4 findings: 1 medium, 3 informational

Put your code through the same review.

This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.

Get a quote