Frankencoin - Ruhum's results

A decentralized and fully collateralized stablecoin.

General Information

Platform: Code4rena

Start Date: 12/04/2023

Pot Size: $60,500 USDC

Total HM: 21

Participants: 199

Period: 7 days

Judge: hansfriese

Total Solo HM: 5

Id: 231

League: ETH

Frankencoin

Findings Distribution

Researcher Performance

Rank: 54/199

Findings: 4

Award: $94.94

🌟 Selected for report: 1

🚀 Solo Findings: 0

Lines of code

https://github.com/code-423n4/2023-04-frankencoin/blob/main/contracts/Equity.sol#L313

Vulnerability details

Impact

The function doesn't burn the funds of all the provided addresses. Subsequent depositors trying to bootstrap the system again will receive fewer shares than they expected since the total supply remains almost unchanged.

Proof of Concept

    function restructureCapTable(address[] calldata helpers, address[] calldata addressesToWipe) public {
        require(zchf.equity() < MINIMUM_EQUITY);
        checkQualified(msg.sender, helpers);
        for (uint256 i = 0; i<addressesToWipe.length; i++){
            address current = addressesToWipe[0];
            _burn(current, balanceOf(current));
        }
    }

It only clears the funds of the address at index 0.

Tools Used

none

Properly loop over all the addresses:

    function restructureCapTable(address[] calldata helpers, address[] calldata addressesToWipe) public {
        require(zchf.equity() < MINIMUM_EQUITY);
        checkQualified(msg.sender, helpers);
        for (uint256 i = 0; i<addressesToWipe.length; i++){
            address current = addressesToWipe[i];
            _burn(current, balanceOf(current));
        }
    }

#0 - c4-pre-sort

2023-04-20T14:23:22Z

0xA5DF marked the issue as duplicate of #941

#1 - c4-judge

2023-05-18T14:28:11Z

hansfriese marked the issue as satisfactory

Findings Information

🌟 Selected for report: Josiah

Also found by: 0xDACA, Diana, Emmanuel, Kumpa, Nyx, RaymondFam, Ruhum, __141345__, bin2chen, carlitox477, lil_eth, nobody2018, rbserver

Labels

bug
2 (Med Risk)
satisfactory
duplicate-932

Awards

28.2764 USDC - $28.28

External Links

Lines of code

https://github.com/code-423n4/2023-04-frankencoin/blob/main/contracts/Position.sol#L97

Vulnerability details

Impact

When cloning a position you can use up the remaining minting limit of it. That will force the owner of that position to create a new one or clone one as well.

Proof of Concept

The reduceLimitForClone() function is supposed to grant half of the position's mint limit to the clone:

    /**
     * Adjust this position's limit to give away half of the remaining limit to the clone.
     * Invariant: global limit stays the same.
     *
     * Cloning a position is only allowed if the position is not challenged, not expired and not in cooldown.
     *
     * @param _minimum amount that clone wants to mint initially
     * @return limit for the clone
     */
    function reduceLimitForClone(uint256 _minimum) external noChallenge noCooldown alive onlyHub returns (uint256) {
        uint256 reduction = (limit - minted - _minimum)/2; // this will fail with an underflow if minimum is too high
        limit -= reduction + _minimum;
        return reduction + _minimum;
    }

But, by setting _minimum so that $minimum = limited - minimum$ you can set limit = minted. Meaning, the position can't mint more ZCHF.

For that, the person cloning has to provide enough collateral to mint the whole amount at the time of cloning.

Tools Used

none

reduceLimitForClone() should remove the _minimum parameter and always decrease the limit by half. If that amount is not enough to fulfill the caller's initial mint, just revert. Force the user to clone a different position or create their own one.

#0 - c4-pre-sort

2023-04-20T09:46:07Z

0xA5DF marked the issue as duplicate of #932

#1 - c4-judge

2023-05-18T14:15:58Z

hansfriese marked the issue as satisfactory

Findings Information

🌟 Selected for report: Ruhum

Also found by: 7siech, DadeKuma, J4de, Lirios, deliriusz, foxb868, hihen, juancito, ladboy233, rbserver, santipu_, zaevlad

Labels

bug
2 (Med Risk)
primary issue
selected for report
sponsor acknowledged
M-13

Awards

43.9854 USDC - $43.99

External Links

Lines of code

https://github.com/code-423n4/2023-04-frankencoin/blob/main/contracts/Frankencoin.sol#L152

Vulnerability details

Impact

The project is supposed to be self-governing. Token owners are able to suggest new minters and collateral. The auction mechanism allows participants to remove collateral from the system if it's deemed unhealthy. But, there's no way to remove a registered minter.

Why would you want to remove a registered minter? Because they can have bugs that could break the whole system. The current minter, MintingHub, for example, implements a novel auction mechanism to price collateral instead of choosing the industry standard Chainlink oracles. While I support the idea of having a fully decentralized system, it does add additional risk to the project. A risk that's taken not only by the protocol team but every ZCHF holder as well.

Obviously, these are just hypotheticals. But, the system is not equipped to handle a scenario where the minter malfunctions.

Proof of Concept

After a minter is suggested you have generally 10 days to deny it. After that, there's no way to remove it:

   function denyMinter(address _minter, address[] calldata _helpers, string calldata _message) override external {
      if (block.timestamp > minters[_minter]) revert TooLate();
      reserve.checkQualified(msg.sender, _helpers);
      delete minters[_minter];
      emit MinterDenied(_minter, _message);
   }

Tools Used

none

Implement the ability for token holders to temporarily pause a minter as well as remove it altogether.

#0 - c4-pre-sort

2023-04-21T14:16:27Z

0xA5DF marked the issue as primary issue

#1 - luziusmeisser

2023-05-03T07:04:07Z

I have thought about the ability to remove old minters, but decided against it.

Instead, experimental minters should come with their own limits (time, pause function, volume limits, etc.). They are free to include that. Minters that do not include it, can be expected to be denied unless they have been really thoroughly audited.

#2 - luziusmeisser

2023-05-03T07:04:46Z

So in fact, it is possible to pause a minter assuming the mintuer supports that functionality.

#3 - c4-sponsor

2023-05-03T07:04:54Z

luziusmeisser marked the issue as sponsor disputed

#4 - c4-sponsor

2023-05-03T07:05:01Z

luziusmeisser marked the issue as sponsor acknowledged

#5 - c4-judge

2023-05-18T05:08:32Z

hansfriese marked the issue as selected for report

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