Skip to main content

💂 Block Guard

Introduction​

The Block Guard module facilitates the flash-loan protection mechanism. It restricts users from calling specific functions within the same block, such as using Multicall, to prevent potential exploits.

Implementation​

The ABlockGuard is a simple contract that tracks the latest block in which a particular resource (group of functions) was accessed by a specific address. It provides several modifiers for easy integration.

FunctionDescription
lockBlockSaves the current block number when a resource is accessed
checkBlockEnsures a resource isn't accessed more than once in the same block
checkLockBlockCombines the functionalities of both checking and locking a resource in a block

Example​

For instance, to prevent users from depositing and withdrawing assets in the same transaction, we can utilize the ABlockGuard contract. By inheriting from the ABlockGuard, we can apply lock modifiers to both deposit and withdraw functions.

import "@solarity/solidity-lib/utils/ABlockGuard.sol";

contract NotFlashloanable is ABlockGuard {
string public constant DEPOSIT_WITHDRAW = "DEPOSIT_WITHDRAW";

function deposit() external lockBlock(DEPOSIT_WITHDRAW, msg.sender) {
/* ... */
}

function withdraw() external checkBlock(DEPOSIT_WITHDRAW, msg.sender) {
/* ... */
}
}

Now, if an attacker tries to deposit and withdraw assets in the same block, our contract will revert.

contract Attacker {
NotFlashloanable public notFlashloanable;

function attack() external {
notFlashloanable.deposit();

// manipulating deposited funds...

notFlashloanable.withdraw(); // Reverts with "BlockGuard: locked"
}
}

Please note that it is still possible to make multiple deposits and withdrawals in the same transaction. Use the checkLockBlock modifier to avoid this.

contract Attacker {
NotFlashloanable public notFlashloanable;

function attack() external {
notFlashloanable.deposit();
notFlashloanable.deposit(); // OK
}
}

Production references​