Skip to main content

Indexing Angstrom L2 Contract Events

Angstrom L2 Hooks are Uniswap V4 hooks. In order to accurately track Angstrom state, indexers are expected to collect the standard Uniswap V4 events.

Angstrom-specific events are emitted both by the L2Factory contract and by individual hook contracts

Indexing All L2 Hooks

When a new Hook is deployed via the Factory, a PoolCreated(address hook, PoolKey key, uint24 creatorSwapFeeE6, uint24 creatorTaxFeeE6, uint24 protocolSwapFeeE6, uint24 protocolTaxFeeE6); event is emitted. Indexers can get the full list of Angstrom L2 hook contracts by aggregating the hook field of these events.

Tracking Fee Configurations

Individual Angstrom L2 Hooks can support multiple Uniswap V4 PoolKeys. For each PoolKey, the Hook has a fee configuration consisting of creatorSwapFeeE6, creatorTaxFeeE6, protocolSwapFeeE6, and protocolTaxFeeE6. For more on these fees, see Pool Fee Configuration within the contract docs.

The initial values of these fees are emitted in the PoolCreated event by the Factory contract. Any subsequent changes to the fees of a PoolKey for a deployed Hook must be initiated by the Factory's owner, and the Factory will emit a ProtocolSwapFeeUpdated(address indexed hook, PoolKey key, uint256 newFeeE6) or ProtocolTaxFeeUpdated(address indexed hook, PoolKey key, uint256 newFeeE6) event as appropriate. Note that once configured, the creatorSwapFeeE6 and creatorTaxFeeE6 of a (hook, PoolKey) tuple cannot be changed.

The default fees -- defaultProtocolSwapFeeAsMultipleE6 and defaultProtocolTaxFeeE6 of the Factory may be modified by the Factory's owner, with corresponding DefaultProtocolSwapFeeE6Updated(uint24 newDefaultProtocolSwapFeeE6) and DefaultProtocolTaxFeeE6Updated(uint24 newDefaultProtocolTaxFeeE6) events.

Note that changes to these values do not affect existing pools, and only apply to new (hook, PoolKey) tuples.

While the Factory's defaultProtocolTaxFeeE6 variable directly corresponds to the protocolTaxFeeE6 of any newly-configured pool, the protocolSwapFeeE6 of a new pool is dependent upon the pool's configured creatorSwapFeeE6 and lpFeeE6, and thus does not directly correspond to the Factory's defaultProtocolSwapFeeAsMultipleE6 variable; the Factory's getDefaultProtocolSwapFee(uint256 creatorSwapFeeE6, uint256 lpFeeE6) function should instead be used to calculate the anticipated protocolSwapFeeE6 for a newly-configured pool.

Fee Accumulation

Basic Fee Accumulation

Angstrom L2 charges both priority-fee based taxes on swaps and liquidity modifications, and fees on swaps. All events related to fee accumulation are emitted by individual Hook contracts, not the Factory.

Any time a Just-In-Time liquidity tax is charged, a ProtocolJITTaxDistributed(PoolId indexed poolId, uint256 amount) is emitted. Note that this tax is always charged in the chain's native currency. These taxes go 100% to the Angstrom protocol and accrue as native token balance of the Factory contract.

Taxes on swaps are split between the pool creator, the Angstrom protocol, and pool LPs. In order to differentiate these streams and facilitate tracking them, Angstrom L2 emits LPTaxDistributed(PoolId indexed poolId, uint256 amount), CreatorTaxDistributed(PoolId indexed poolId, uint256 amount), and ProtocolSwapTaxDistributed(PoolId indexed poolId, uint256 amount) events. Note that since the tax is always charged in the chain's native currency, these events do not have any 'currency' field. LP taxes accrue as ERC6909 tokens held by the individual Hook contract (see below for understanding how to calculate rewards for specific LP positions), creator taxes accrue as native token balance of the Hook contract, and protocol taxes accrue as native token balance of the Factory contract.

Fees on swaps are split between the pool creator and the Angstrom protocol, with corresponding CreatorFeeDistributed(PoolId indexed poolId, Currency indexed feeCurrency, uint256 amount) and ProtocolFeeDistributed(PoolId indexed poolId, Currency indexed feeCurrency, uint256 amount) events. Creator fees accrue as ERC20 or native currency balances of the Hook contract, while protocol fees accrue as balances of the Factory contract.

Liquidity Position-Specific Rewards Calculation

LP taxes are split across active Liquidity Providers, using an accounting mechanism similar to Uniswap V3/V4. For a detailed description of the underlying mechanism, see this page.

When rewards from LP taxes are distributed, the Hook contract emits corresponding GrowthOutsideX128Increased(PoolId indexed poolId, int24 tick, uint256 growthX128) and GlobalGrowthX128Increased(PoolId indexed poolId, uint256 growthX128) events.

An individual LP position accrues rewards equal to growthInsideX128 * liquidity / (2**128) where liquidity is a property of the LP position and growthInsideX128 can be calculated via the PoolRewards.getGrowthInsideX128(PoolRewards storage self, int24 currentTick, int24 lowerTick, int24 upperTick) function which parallels Uniswap V3/V4 fee calculations.

Withdrawal of Revenue

A Hook creator can withdraw their accrued revenue at any time by calling the AngstromL2.withdrawCreatorRevenue(Currency currency, address to, uint256 amount) function. A corresponding CreatorRevenueWithdrawn(Currency indexed currency, address indexed to, uint256 amount) event is emitted by the Hook contract.

The owner of the Factory contract can withdraw accrued revenue by calling the Factory's withdrawRevenue(Currency currency, address to, uint256 amount) function. A corresponding ProtocolRevenueWithdrawn(Currency indexed currency, address indexed to, uint256 amount) event is emitted by the Factory contract.

Emergency State Changes

The WithdrawOnly() event is emitted by the Factory when switching irrevocably to withdraw-only mode. New hook deployment is immediately, permanently paused on the Factory.

Subsequently, once the pullWithdrawOnly() function is called on an individual hook contract, the hook irrevocably enters withdraw-only mode and emits a WithdrawOnlyModeActivated() event. Swaps & adding liquidity are permanently paused on the hook; additionally, LP rewards earned from swap fees are effectively zeroed out.