Re-entrancy

Re-entrancy has been a long-standing problem within the space and has resulted in various catastrophic loss of funds.

Often, re-entrancy bugs have risen from a composability problem, where leaving the contract, calling some arbitrary code and then re-entering the contract, lead to unforeseen consequences -- it isn't safely composable. With the addition of potentially complex delegatecall chains between Extensions, the composability problem heightens the risk of potential re-entrancy exploits.

To combat the problems we have highlighted three main types of re-entrancy and provided guards against all types to give better assurances that when you write code with a specific intent, you can protect against future unknown execution.

The three types of re-entrancy:

  • Atomic re-entrancy

  • External re-entrancy

  • Absolute re-entrancy

Atomic Re-entrancy

Atomic re-entrancy is a type of re-entrancy where a function, once called, is attempted to be called a second time later in the call-stack.

This can happen if during the function call, a call to another function occurs which in turn attempts to call the original function a second time anywhere down the callchain. This can also happen with a simple recursive function.

This re-entrancy is relevant if there is a function that you do not want to be called more than once, but you want to allow the rest of the contract to be re-entered.

Guard

Use the nonReentrant modifier to guard against atomic re-entrancy.

Any function modified with the nonReentrant modifier cannot be called twice in the same call-stack.

External Re-entrancy

External re-entrancy is a type of re-entrancy where a contract is re-entered through any function from an external source. This means that a contract function is called by an external contract or user and the call-stack leaves the current contract, and then later attempts to re-enter the contract through any other function.

This can happen if during the function call, a call to an external contract function occurs which in turn attempts to call either the original function or any other function owned by the origin contract.

This re-entrancy is relevant if you want to prevent a contract to be re-entered from outside more than once, but still want to keep internal function calls between Extensions unrestricted.

Guard

Use the externalNonReentrant modifier to guard against external re-entrancy.

Any function modified with the externalNonReentrant modifier cannot be called by an external source if another function in this contract has already been called by an external source previously in the current call-stack. Importantly, functions that have been modified with this can still be called by other functions internal to the contract.

Absolute Re-entrancy

Absolute re-entrancy is a type of re-entrancy where a contract is re-entered through any source. This means that once a contract function is called, it is considered entered, can any other call to a function owned by that contract is considered a re-entrant.

This re-entrancy is relevant in the most strict and security-sensitive use-cases where you want to prevent any kind of potential re-entrancy. Use the guard to prevent any additional function calls to a contract once another function has already been called in a call-stack.

Guard

Use the strictNonReentrant modifier to guard against absolute re-entrancy.

Any function modified with the strictNonReentrant modifier cannot be called if any other function from the same contract has already been called previously in the call-stack.

Last updated