Popular tags

    How to protect my contract from reentrancy in Cairo Language / StarkNet?


    3 months ago




    Everyone knows that secure code is essential. Can someone explain what is reentrancy? I am curious about the reentrancy attack in StarkNet – is it a problem in Cairo Language and how to protect my smart contract from this attack?




    3 months ago

    1 answers


    Accepted answer

    Reentrancy is a very common attack in smart contracts, due to contracts often being required to call other contracts. As we cannot control what another contract does, it might be possible that the called contract initiates a callback to the original contract. This can be very dangerous if the original contract does not follow the checks-effects-interaction pattern, which states that we should not make changes to state variables after interacting with an external entity.

    For instance, let's take a (very generalized) contract which stores users balances and allows to make transfers using arbitrary tokens. In this case, the pattern should be the following:

    • Check that the user has enough funds to transfer
    • Decrease the balance of the sender and increase the balance of the receiver
    • Perform the transfer using the external token contract

    Should step 2 and 3 be inverted, and the arbitrary contract called would perform a callback to our original contract, the balance of the user would not have been updated and another transfer could be made on its behalf.

    On top of following the checks-effects-interaction pattern, we can use Reentrancy guards to protect our contracts. In Cairo, we have OpenZeppelin's implementation.

    This is as simple as calling ReentrancyGuard._start() at the beginning of a function, and ReentrancyGuard._end() at the end. This will prevent any reentrant call in the code, as if the funciton is reentered, it will error out due the storage variable ReentrancyGuard_entered being set to true. An example below:

    @external func callback{syscall_ptr: felt*, pedersen_ptr: HashBuiltin*, range_check_ptr}() { ReentrancyGuard._start(); _count(); ReentrancyGuard._end(); return (); }



    3 months ago

    Your answer