Flash Accounting

Hello EIP-1153 and Lock & Call

Before diving into flash accounting, it's important to understand the landscape of Ethereum transactions. Typically, each operation within a smart contract requires a set amount of computational power, or "gas," to be spent. This becomes a constraint, especially when you're dealing with complex functions and multiple interactions with different smart contracts. The cost can add up quickly and become a barrier to efficient operations.

Enter flash accounting, a new feature introduced alongside the singleton-style pool management in Uniswap V4. What flash accounting does is revolutionize the way tokens are handled during transactions. Unlike traditional methods where token balances would need to be explicitly accounted for at each step, flash accounting operates on the principle that no tokens are owed to either the pool or the caller by the end of the transaction or "lock period."

Here's a snippet from the PoolManager contract that highlights the use of flash accounting:

/// @inheritdoc IPoolManager
function lock(bytes calldata data) external override returns (bytes memory result) {
    lockData.push(msg.sender);

    // the caller does everything in this callback, including paying what they owe via calls to settle
    result = ILockCallback(msg.sender).lockAcquired(data);

    if (lockData.length == 1) {
        if (lockData.nonzeroDeltaCount != 0) revert CurrencyNotSettled();
        delete lockData;
    } else {
        lockData.pop();
    }
}

function _accountDelta(Currency currency, int128 delta) internal {
    if (delta == 0) return;

    address locker = lockData.getActiveLock();
    int256 current = currencyDelta[locker][currency];
    int256 next = current + delta;

    unchecked {
        if (next == 0) {
            lockData.nonzeroDeltaCount--;
        } else if (current == 0) {
            lockData.nonzeroDeltaCount++;
        }
    }

    currencyDelta[locker][currency] = next;
}

/// @dev Accumulates a balance change to a map of currency to balance changes
function _accountPoolBalanceDelta(PoolKey memory key, BalanceDelta delta) internal {
    _accountDelta(key.currency0, delta.amount0());
    _accountDelta(key.currency1, delta.amount1());
}

modifier onlyByLocker() {
    address locker = lockData.getActiveLock();
    if (msg.sender != locker) revert LockedBy(locker);
    _;
}

Flash accounting leverages the capabilities of transient storage opcodes, as proposed in EIP-1153. These transient storage opcodes are incredibly efficient, acting like temporary variables that exist only for the duration of the transaction. This dramatically reduces the gas costs because you're not continually updating the Ethereum state with intermediate steps.

In practical terms, flash accounting is a boon for developers and traders alike. For developers, it simplifies the task of tracking token balances during complex transactions. For traders, it slashes the gas fees when conducting trades that span multiple pools. Furthermore, it opens up new possibilities for complex and innovative integrations with Uniswap V4, effectively making the protocol more versatile and user-friendly.

Last updated