Canto Invitational

Canto is a next generation L1 designed to deliver on the promise of DeFi.

  • Start date29 Mar 2024
  • End date3 Apr 2024
  • Total awards$13,500
  • Duration5 days

Canto audit details

  • Total Prize Pool: $13,500

    • HM awards: $9,900
    • Analysis awards: $500
    • QA awards: $300
    • Gas awards: $300
    • Judge awards: $2,000
    • Scout awards: $500

    ❗️Awarding Note for Wardens, Judges, and Lookouts: If you want to claim your awards in $ worth of CANTO, you must follow the steps outlined in this thread; otherwise you'll be paid out in USDC.

  • Join C4 Discord to register

  • Submit findings using the C4 form

  • Read our guidelines for more details

  • Starts March 29, 2024 20:00 UTC

  • Ends April 3, 2024 20:00 UTC

Automated Findings / Publicly Known Issues

The 4naly3er report can be found here.

Note for C4 wardens: Anything included in this Automated Findings / Publicly Known Issues section is considered a publicly known issue and is ineligible for awards.


Application Specific Dollar Omnichain Fungible Token (asD-OFT)


asD allows for protocols to earn yield on their users' dollar deposits. asD is always pegged to 1 NOTEandthisNOTE and this NOTE can be deposited into the Canto Lending Market to accrue interest. This version of asD implements LayerZero's Omnichain Fungible Token to allow creators from any LayerZero supported chain to earn extra revenue from all stable coin deposits.

Useful background information

asD Flow

The purpose of implementing cross chain functionality with asD is to allow developers from any supported chain to earn Canto Lending Market yield without needing to directly deploy their entire protocol on the Canto application layer. By using Layer Zero v2, we can accomplish this by bridging whitelisted stable coins to mint asD tokens that can then be bridged back to the original application.

asD Flow



The ASDOFT contract is a direct implementation of the ASD ERC20 token used for 1155Tech however it also implements LayerZero v2 OFT functionality. This allows for asD tokens minted on Canto as well as easily bridged back to the source application to be used in the protocol.

In order to ensure a 1:1 peg to $NOTE, only the ASDOFT should be deployed on Canto for minting, and regular OFT implementations should be deployed on all other supported chains.


The ASDRouter contract allows for the minting of asD tokens to be done in a single transaction originating from any supported chain. A stable coin represented as an OFT is sent to the ASDRouter with "lzCompose" options passed to tell the Layer Zero executor to call lzCompose once it receives the message.

 function lzCompose(
    address _from,
    bytes32 _guid,
    bytes calldata _message,
    address _executor,
    bytes calldata _extraData) external payable;

A user who wants to obtain asD tokens must send their stable assets to the ASDRouter through Layer Zero. The _message must be formatted as bytes with the form of the OFTComposeMessage struct:

struct OftComposeMessage {
    uint32 _dstLzEid; // destination endpoint id
    address _dstReceiver; // receiver on destination
    address _dstAsdAddress; // asD address on destination
    address _cantoAsdAddress; // asD on Canto (where to mint asD from)
    uint256 _minAmountASD; // minimum amount (slippage for swap)
    address _cantoRefundAddress; // canto refund address
    uint256 _feeForSend; // fee for bridge to destination chain

This struct tells the Router which asD tokens to mint and where to send them after they are obtained. The lzCompose function on the Router performs the following steps

  1. Deposits stable coin for asdUSDC
  2. Swaps asdUSDC in ambient pool for $NOTE
  3. Deposits $NOTE to asD Vault for asD tokens
  4. Sends asD tokens to destination chain and address

After lzCompose has been called, the Router should never have any tokens left over (all tokens are refunded or sent). With Layer Zero execution, if the lzCompose reverts, the OFT tokens are still received by the Router, but the compose message can be retried. Because of this, the Router protects against reverts by implementing saftey checks and refunds during each step. All refunds will be sent to the user's address on Canto. For any message that contains msg.value, the entire amount will also be refunded to the user as Canto.

Saftey checks:

  1. Incorrect compose message formatting (OFT refunded)
  2. Not whitelisted stable coin version (OFT refunded)
  3. Unsuccessful swap to $NOTE (usdcOFT refunded)
  4. Unsuccessful deposit into asD vault ($NOTE refunded)
  5. Unsuccessful bridge of asD to destination of insufficient fee (asD refunded)


ASDUSDC is a simple wrapper for all of the different representations for the same stable coins that might be bridged through Layer Zero. The purpose of this is to limit the amount of pools needed for swapping tokens to $NOTE. With this wrapper, only one pool is needed and all OFT's representing the same can be wrapped into ASDUSDC and swapped for Note easily. A user can deposit any of the whitelisted usdc versions to mint ASDUSDC as well as withdraw any of those same versions (as long as there is enough locked) by burning their ASDUSDC.



Files in scope

FileLogic ContractsInterfacesSLOCPurposeLibraries used
/contracts/clm/CTokenInterfaces.sol****212Interaction with Compound Lending Market cTokens****
/contracts/clm/Turnstile.sol****13Registers contract to CSR (contract secured revenue)****
/contracts/asd/asdOFT.sol1****47Mints and burns ASD tokens by depositing/withdrawing $NOTE and supplying/withdrawing from Canto Lending MarketERC20, OFT, CErc20Interface
/contracts/asd/asdRouter.sol1****138Routes stable OFTs to correct ASD vault and returns to user on destination chain in a single transactionOptionsBuilder, IOFT, OFTComposeMsgCodec, IOAppComposer
/contracts/asd/asdUSDC.sol1****40Wrapper for different OFT representations of the same underlying token to be used in dexERC20
/contracts/ambient/CrocInterfaces.sol****27Interface for ambient dex for router to swap for Note****

Files out of scope


Scoping Q & A

General questions

ERC20 used by the protocolLayer Zero OFT, USDC
Test coverage75%
ERC721 used by the protocolNone
ERC777 used by the protocolNone
ERC1155 used by the protocolNone
Chains the protocol will be deployed onEthereum, Arbitrum, Polygon, OtherCanto

ERC20 token behaviors in scope

  • The only tokens in scope are: Layer Zero OFT, USDC
  • Vulnerabilities related to these token behaviours are only considered valid if they actually exist in tokens which are used, i.e. Layer Zero OFT, USDC.

External integrations (e.g., Uniswap) behavior in scope:

Enabling/disabling fees (e.g. Blur disables/enables fees)No
Pausability (e.g. Uniswap pool gets paused)No
Upgradeability (e.g. Uniswap gets upgraded)No

EIP compliance checklist


Additional context

Main invariants

  1. ASDRouter native balance should always be zero.
  2. ASDRouter balance of any token should always be zero after lzCompose has completed
  3. ASDUSDC usdcBalances mapping should always sum to the totalSupply

Attack ideas (where to focus for bugs)

  • Since Layer Zero executors call lzCompose after sending funds to the ASDRouter Contract, this lzCompose function should never revert.
  • All external calls should be checked for success and decoding bytes must never fail.
  • All errors should result in refunds so that tokens do not get trapped in Layer Zero Protocol.

All trusted roles in the protocol

ASDUSDC ownerSets whitelist for tokens

Describe any novel or unique curve logic or mathematical models implemented in the contracts:


Running tests

git clone

git submodule update --init --recursive

npm install

npx hardhat compile

npx hardhat test

To run code coverage

npx hardhat coverage

To run gas benchmarks

REPORT_GAS=true npx hardhat test



Employees of Canto and employees' family members are ineligible to participate in this audit.