> For the complete documentation index, see [llms.txt](https://docs.kairosswap.com/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.kairosswap.com/protocol/events.md).

# Events

Reference for every integrator-facing event that SwapCore (or a library it delegatecalls into) emits. Use these to drive indexers, subgraphs, monitoring dashboards, and UI feeds.

Sources:

* `lib/SwapEvents.sol` — most event declarations (SwapCore inherits this).
* `lib/Utils.sol` — declares `BuyerTransferFailed` and emits it from the settlement / liquidation paths. Because `Utils` is a Solidity library that SwapCore delegatecalls, the event is emitted from the SwapCore address, so indexers can subscribe to the SwapCore address as the sole log source.

Event topic signatures below are the canonical `keccak256("EventName(type1,type2,...)")` — use them as the `topic[0]` filter in log queries.

***

## Lifecycle events

### MarketCreated

```solidity
event MarketCreated(
    bytes32 indexed marketId,
    address indexed creator,
    address         referenceRateOracle,
    address         baseSwapRateOracle,
    address indexed swapToken,
    uint64          leverageMultiplier,
    uint32          swapTerm,
    Types.RateType  rateType,
    bytes32         correspondingMarketId
);
```

Emitted once per side of the pair from `createMarket` → `_initializeMarket`. A single `createMarket` call therefore produces **two** `MarketCreated` events, one with `rateType = 0` (BUY\_FIXED) and one with `rateType = 1` (BUY\_FLOATING). Use `correspondingMarketId` to stitch them together into a pair.

Indexed topics: `marketId`, `creator`, `swapToken`.

### MarketConfigured

```solidity
event MarketConfigured(
    bytes32 indexed marketId,
    uint32  numBuckets,
    uint32  bucketInterval,
    uint256 utilFeeSlopeWad,
    uint256 kinkUtilization,
    uint256 maxKinkFeeWad,
    uint256 earlyExitFee,
    uint256 liquidationIncentive,
    address riskPremiumOracle,
    bool    lpWhitelistEnabled,
    address marketOwner,
    uint88  minCollateral
);
```

Emitted alongside `MarketCreated` from `_initializeMarket`, carrying the rest of the config that didn't fit in `MarketCreated`. Use this to snapshot the full market configuration at creation time. The economic parameters (fee curve, buckets, oracles, term, collateral) are immutable — nothing in SwapCore rewrites them — so one `MarketConfigured` is all an indexer needs for those. The one field here that can change later is `marketOwner`: track `MarketOwnerChanged` to keep it current.

### MarketCreationFeeCollected

```solidity
event MarketCreationFeeCollected(
    bytes32 indexed fixedMarketId,
    bytes32 indexed floatingMarketId,
    address indexed creator,
    address feeToken,
    uint256 feeAmount
);
```

Emitted once per `createMarket` call **if** a creation fee was configured in `Admin` at call time. `feeToken == address(0)` means the fee was paid in ETH; otherwise it's the ERC20 token address. Paired with `MarketCreated` events on the two market IDs.

***

## Ownership & admin

### MarketOwnershipTransferStarted

```solidity
event MarketOwnershipTransferStarted(
    bytes32 indexed marketId,
    address indexed currentOwner,
    address indexed newOwner
);
```

Emitted by `transferMarketOwnership`. Marks the start of the 2-step handoff. `newOwner == address(0)` means an in-flight transfer was cancelled.

### MarketOwnerChanged

```solidity
event MarketOwnerChanged(bytes32 indexed marketId, address newOwner);
```

Emitted by `acceptMarketOwnership` when the pending owner accepts the role. `newOwner` is the new owner (`msg.sender` of `acceptMarketOwnership`).

### MarketLpWhitelistUpdated

```solidity
event MarketLpWhitelistUpdated(
    bytes32 indexed marketId,
    address indexed lp,
    bool    isWhitelisted
);
```

Emitted by `setMarketLpWhitelist`. Only meaningful on markets created with `lpWhitelistEnabled = true`.

### MarketAdminChange

```solidity
event MarketAdminChange(bytes32 indexed marketId, string controlType, bool isPaused);
```

Emitted by `terminateMarket` with `controlType = "terminateMarket"` and `isPaused = true`. The `string` and `bool` arguments exist for forward-compatibility with future admin levers, but today this event only ever fires for termination.

***

## Liquidity

### CollateralSupplied

```solidity
event CollateralSupplied(
    bytes32 indexed marketId,
    address indexed onBehalfOf,
    address caller,
    uint256 amount,
    uint256 sharesMinted,
    uint256 sharePrice,
    uint256 entryPrice,
    uint64  vestEndTimestamp
);
```

Emitted by `supplyCollateral`. `onBehalfOf` is the address that got the shares; `caller` is `msg.sender` (same unless a bundler is acting). `sharePrice` is the MtM price at mint. `entryPrice` and `vestEndTimestamp` are the LP's profit-vest anchor and window end set by this deposit.

### CollateralTokenWithdrawn

```solidity
event CollateralTokenWithdrawn(
    bytes32 indexed marketId,
    address indexed onBehalfOf,
    address caller,
    address receiver,
    uint256 amount,
    uint256 sharesRedeemed,
    uint256 sharePrice,
    bool    capApplied
);
```

Emitted by `withdrawCollateral`. `amount` is in `swapToken` decimals and was delivered to `receiver` (which may differ from both `onBehalfOf` and `caller` when a bundler passes itself as `receiver` to forward the redeemed tokens elsewhere). `capApplied` is `true` when the profit-vest cap bound the burn (shares priced at `entryPrice` rather than the live `sharePrice`).

***

## Swap lifecycle

### SwapCreated

```solidity
event SwapCreated(
    bytes32 indexed marketId,
    bytes32 indexed swapId,
    address indexed onBehalfOf,
    address caller,
    uint256 notionalAmount,
    uint256 buyerCollateral,
    uint256 poolCollateralBacking,
    int256  swapRate,
    int256  baseRate,
    uint256 entryTimestamp,
    uint256 entryFloatingIndex,
    uint256 utilFee,
    uint256 riskPremium,
    uint32  swapTerm,
    uint8   rateType,
    uint256 protocolFee,
    uint256 liquidationBounty
);
```

Emitted by `buySwap`. The indexer reconstructs a position from this event alone — every field that `makePayment` will need later is included. `swapRate` is the all-in rate locked by the buyer; `baseRate`, `utilFee`, and `riskPremium` are broken out for analytics.

### SwapClosed

```solidity
event SwapClosed(
    bytes32 indexed marketId,
    bytes32 indexed swapId,
    address indexed onBehalfOf,
    address caller,
    uint8   closureType,            // 0 = expired, 1 = earlyExit, 2 = liquidated
    uint256 buyerCollateralReleased,
    uint256 lpCollateralReleased,
    uint256 amountSettled,
    uint256 totalPaymentsMade,
    uint8   netRecipient,           // 0 = LP receives, 1 = buyer receives
    uint256 floatingPayment,        // UNSIGNED accrued-leg magnitude; display-only
    uint256 fixedPayment,           // UNSIGNED accrued-leg magnitude; display-only
    uint256 earlyExitFee,           // fee actually retained; may be < configured (even 0) when payout is backing-capped; 0 for non-early-exit
    int256  floatingRate,           // annualized floating rate realized over the period (WAD; can be negative)
    int256  netSettlement           // signed realized net transfer, buyer perspective; = ±amountSettled per netRecipient
);
```

Emitted once per swap from every closure path: `makePayment`, `exitSwapEarly`, and `liquidateSwap`. Branch on `closureType` to distinguish.

For normal expiry and early exit, `floatingPayment` / `fixedPayment` carry the absolute leg amounts over the settled period and `floatingRate` is the realized annualized floating rate that drove them. For liquidations, `floatingPayment`, `fixedPayment`, and `earlyExitFee` are all `0` (not computed — liquidation uses an accrual model rather than full settlement math), but `floatingRate` **is** populated: it's the rate that drove the `Utils.calculateLiquidationObligation` decision, reused here rather than recomputed.

`netSettlement` is the signed realized net transfer from the **buyer's perspective** — positive when the buyer received, negative when the buyer paid, with magnitude equal to `amountSettled`. It encodes direction and magnitude in one field, so an indexer can use `netSettlement` alone instead of combining `amountSettled` with `netRecipient`.

### SwapLiquidated

```solidity
event SwapLiquidated(
    bytes32 indexed marketId,
    bytes32 indexed swapId,
    address indexed liquidatedParty,
    bool    buyerLiquidated,
    bool    poolLiquidated,
    uint256 collateralTransferred,
    address liquidator
);
```

Emitted by `liquidateSwap` **in addition to** `SwapClosed`. Use this when you need the liquidator identity or the boolean flags distinguishing a buyer-side vs. pool-side liquidation. `liquidatedParty` is the buyer's address (`swap.userAddress`) on a **buyer-side** liquidation, and `address(0)` on a **pool-side** liquidation — the liquidated party is the LP pool, which has no single address, so the field is left zero and you read `poolLiquidated == true` instead. Exactly one of `buyerLiquidated` / `poolLiquidated` is `true` in a real liquidation; both being `false` is a defensive path that shouldn't occur in production.

### SwapTransferred

```solidity
event SwapTransferred(
    bytes32 indexed swapId,
    address indexed previousOwner,
    address indexed newOwner,
    address caller
);
```

Emitted by `transferSwapPosition`. The `caller` field captures whether the transfer was done directly (`caller == previousOwner`) or via a delegate (`caller != previousOwner`, typically the wrapper / bundler).

### PoolCollateralZeroed

```solidity
event PoolCollateralZeroed(bytes32 indexed marketId);
```

Emitted when settlement **or a pool-side liquidation** drives the LP pool's collateral to zero (the pool lost its entire position). Rare — the last-LP guard and bucket accounting usually prevent this from happening except in extreme-loss scenarios. Monitor this event for risk dashboards; it's the canonical "pool wiped" signal.

***

## Settlement escrow

### BuyerTransferFailed

```solidity
event BuyerTransferFailed(
    bytes32 indexed swapId,
    address indexed recipient,
    uint256 amount
);
```

Declared and emitted inside `Utils._transferOrEscrow`. Because Utils is a Solidity library, the emit happens in SwapCore's execution context and indexers should subscribe to the SwapCore address.

Fires when SwapCore couldn't deliver `amount` of `swapToken` to `recipient` during `_settleSwaps` or `liquidateSwap` (typically a blacklisted recipient). The amount is then held in `escrowedCollateral[swapId]` for later retrieval via `claimEscrow`. Pair with `EscrowClaimed` for the full failed-then-recovered cycle.

### EscrowClaimed

```solidity
event EscrowClaimed(
    bytes32 indexed swapId,
    address indexed recipient,
    address caller,
    uint256 amount
);
```

Emitted by `claimEscrow`. `recipient` is always the original `swap.userAddress` regardless of who called `claimEscrow` — the `caller` field captures the delegate (or the owner themselves).

***

## Fees

### ProtocolFeeCollected

```solidity
event ProtocolFeeCollected(
    bytes32 indexed marketId,
    address indexed buyer,
    uint256 feeAmount
);
```

Emitted by `buySwap` when `protocolFee > 0` **and** the protocol's share was successfully delivered to the multisig. `feeAmount` is the **total** fee charged to the buyer — use `CreatorFeeCollected` (if also present in the same tx) to break out how much of that went to the market creator vs. the protocol multisig. If the multisig can't receive the fee, SwapCore emits [`ProtocolFeeForegone`](#protocolfeeforegone) instead of `ProtocolFeeCollected` (even though `protocolFee > 0`) and refunds the payer, so don't treat the absence of `ProtocolFeeCollected` on a swap as "no fee was charged."

### ProtocolFeeForegone

```solidity
event ProtocolFeeForegone(
    bytes32 indexed marketId,
    address indexed payer,
    uint256 amount
);
```

Emitted when a protocol/creation fee that was charged could **not** be delivered to the multisig (e.g. the multisig is a contract that reverts on receive, or a blacklisted recipient), so the `amount` was refunded to `payer` (`msg.sender`) rather than collected. Fires from two paths: `buySwap` (in place of `ProtocolFeeCollected`, for the protocol fee) and `createMarket` (in place of `MarketCreationFeeCollected`, for the ETH creation fee). For accounting, treat a swap/market with `ProtocolFeeForegone` as "fee waived — payer made whole," not "fee collected."

### CreatorFeeCollected

```solidity
event CreatorFeeCollected(
    bytes32 indexed marketId,
    address indexed creator,
    uint256 feeAmount
);
```

Emitted by `buySwap` when a creator fee split is configured (`Admin.creatorFeeShare > 0`) and the graceful transfer to `market.marketOwner` succeeded. `feeAmount` here is the **creator's portion only**; subtract from `ProtocolFeeCollected.feeAmount` in the same tx to recover the multisig's portion. If the transfer to the market owner failed (rare, happens when the owner is a contract that reverts on receive), the event is **not** emitted and the full protocol fee is sent to the multisig.

***

## Authorization

### AuthorizationSet

```solidity
event AuthorizationSet(
    address indexed authorizer,
    address indexed authorized,
    bool    isAuthorized
);
```

Emitted by `setAuthorization`. `authorizer` is the account whose authorization list changed; `authorized` is the delegate; `isAuthorized` is the new state.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.kairosswap.com/protocol/events.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
