# 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 — later config is not mutable (nothing in SwapCore rewrites these fields), so a single `MarketConfigured` is all an indexer needs per market.

### 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 token,
    address indexed onBehalfOf,
    address caller,
    uint256 amount,
    uint256 sharesMinted,
    uint256 sharePrice
);
```

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.

### CollateralTokenWithdrawn

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

Emitted by `withdrawCollateral`. `amount` is in `swapToken` decimals and was delivered to `caller` (which may differ from `onBehalfOf` when a bundler is involved).

***

## 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
);
```

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,
    uint256 fixedPayment,
    uint256 earlyExitFee            // 0 for non-early-exit closures
);
```

Emitted **once per swap** from every closure path: `makePayment`, `exitSwapEarly`, and `liquidateSwap`. Branch on `closureType` to distinguish. For liquidations, `floatingPayment` and `fixedPayment` are `0` (not computed — liquidation uses an accrual model instead of the full settlement math) and `earlyExitFee` is `0`.

### 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 == address(0)` when neither side was technically "the loser" (e.g., dust liquidation). 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 inside `_settleSwaps` when settlement caused the LP pool's collateral to hit 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 token,
    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`. `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.

### 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: 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:

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

The question should be specific, self-contained, and written in natural language.
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.
