# BullshotFactory Contract API Documentation

## Overview

BullshotFactory is the main entry point of the Bullshot Protocol. It deploys BCToken and BondingCurve contracts using ERC1167 minimal proxy cloning (gas-efficient), tracks all created tokens, and emits global Buy/Sell events forwarded from individual bonding curves.

**Key Features:**
- Permissionless token and bonding curve deployment via clone factory pattern
- Configurable buy/sell/launch/creation fees (owner-controlled)
- Paginated token list query
- Global event indexing for all trades across all tokens

---

## Constants

| Name | Type | Value | Description |
|------|------|-------|-------------|
| `FEE_DENOMINATOR` | `uint16` | **1000** | Denominator for fee calculations (per-mille) |

---

## State Variables

### Fee Configuration

| Name | Type | Visibility | Current Value | Description |
|------|------|------------|---------------|-------------|
| `buyFeePercent` | `uint8` | public | **10** (= 1%) | Fee charged on buys. Expressed in per-mille. Added on top of `amountIn` |
| `sellFeePercent` | `uint8` | public | **10** (= 1%) | Fee charged on sells. Deducted from `amountOut` |
| `launchFeePercent` | `uint8` | public | set by owner | Fee taken from the ETH pool balance at the moment of DEX launch |
| `creationFeeAmount` | `uint256` | public | **150000000000000** wei (0.00015 BNB) | Fixed BNB fee required to create a new token |
| `feeRecipient` | `address payable` | public | set by owner | Address receiving all protocol fees |

### Infrastructure

| Name | Type | Visibility | Description |
|------|------|------------|-------------|
| `uniswapV2Router` | `address` | public | PancakeSwap V2 Router address |
| `uniswapV2Factory` | `address` | public | PancakeSwap V2 Factory address |
| `isBondingCurveAddress` | `mapping(address => bool)` | public | Maps BondingCurve address → `true` if deployed by this factory |
| `tokens` | `BCToken[]` | public | Array of all BCToken contracts ever created |

---

## Events

### Created

Emitted when a new token and bonding curve pair are deployed.

```solidity
event Created(
    address indexed bondingCurve,
    address indexed token,
    address indexed pair,
    address creator
);
```

**Parameters:**
- `bondingCurve`: Address of the cloned BondingCurve
- `token`: Address of the cloned BCToken
- `pair`: PancakeSwap pair address at creation time (`address(0)` — set on first buy)
- `creator`: `msg.sender` who called `createToken`

---

### Buy

Emitted when any user buys on any bonding curve managed by this factory.

```solidity
event Buy(
    address indexed bc,
    address indexed token,
    address indexed buyer,
    uint amountIn,
    uint amountOut
);
```

**Parameters:**
- `bc`: The BondingCurve contract address
- `token`: The BCToken address
- `buyer`: Buyer's wallet address (`to` parameter from the buy call)
- `amountIn`: BNB spent (excluding fee), in wei
- `amountOut`: Token amount received, in wei

---

### Sell

Emitted when any user sells on any bonding curve managed by this factory.

```solidity
event Sell(
    address indexed bc,
    address indexed token,
    address indexed seller,
    uint amountIn,
    uint amountOut
);
```

**Parameters:**
- `bc`: The BondingCurve contract address
- `token`: The BCToken address
- `seller`: Seller's wallet address (`msg.sender` in the sell call)
- `amountIn`: Token amount sold, in wei
- `amountOut`: BNB received (after fee), in wei

---

## Public Functions

### createToken

```solidity
function createToken(
    string memory name,
    string memory ticker,
    uint256 initAmountIn
) external payable
```

Deploys a new BCToken and BondingCurve pair, then optionally performs an initial buy on behalf of the creator.

**Parameters:**
- `name`: Token full name (e.g. `"Bullshot"`)
- `ticker`: Token symbol (e.g. `"BULL"`)
- `initAmountIn`: BNB amount in wei to spend on initial buy. Pass `0` to skip.

**`msg.value` formula:**
```
msg.value = initAmountIn
          + (initAmountIn * buyFeePercent / FEE_DENOMINATOR)
          + creationFeeAmount
```

**Example (no initial buy, 0.01 BNB creation fee):**
```javascript
const creationFee = await factory.creationFeeAmount();
await factory.createToken("Bullshot", "BULL", 0, { value: creationFee });
```

**Example (0.5 BNB initial buy, 0.01 BNB creation fee, 1% buy fee):**
```javascript
const initAmountIn = ethers.utils.parseEther("0.5");
const buyFeePercent = await factory.buyFeePercent(); // e.g. 10
const FEE_DENOMINATOR = 1000;
const creationFee = await factory.creationFeeAmount();
const buyFee = initAmountIn.mul(buyFeePercent).div(FEE_DENOMINATOR);
const value = initAmountIn.add(buyFee).add(creationFee);
await factory.createToken("Bullshot", "BULL", initAmountIn, { value });
```

**Effects:**
1. Transfers `creationFeeAmount` BNB to `feeRecipient`
2. Clones a new `BondingCurve` and a new `BCToken` using ERC1167
3. Registers the bonding curve in `isBondingCurveAddress`
4. Pushes the token to the `tokens` array
5. Initializes both contracts
6. Emits `Created`
7. If `initAmountIn > 0`, calls `bondingCurve.buy(...)` with the remaining value

---

### getTokensLength

```solidity
function getTokensLength() external view returns (uint256)
```

Returns the total number of tokens ever created through this factory.

---

### getTokensList

```solidity
function getTokensList(
    uint256 startIndex,
    uint256 count
) external view returns (BCToken[] memory)
```

Returns a paginated slice of the `tokens` array.

**Parameters:**
- `startIndex`: First index to include (0-based)
- `count`: Number of elements to return

**Returns:** Array of `BCToken` addresses (may be shorter than `count` if end of array is reached)

**Example:**
```javascript
// Get first 20 tokens
const tokens = await factory.getTokensList(0, 20);

// Get next 20 tokens
const tokens2 = await factory.getTokensList(20, 20);
```

---

### setFee

```solidity
function setFee(
    uint256 creationFeeAmount_,
    uint8 buyFeePercent_,
    uint8 sellFeePercent_,
    uint8 launchFeePercent_,
    address payable feeRecipient_
) public onlyOwner
```

Updates all protocol fee parameters. Only callable by the contract owner.

**Parameters:**
- `creationFeeAmount_`: New fixed creation fee in wei
- `buyFeePercent_`: New buy fee per-mille
- `sellFeePercent_`: New sell fee per-mille
- `launchFeePercent_`: New launch fee per-mille
- `feeRecipient_`: New fee recipient address

---

## Example Usage

### Listen for New Token Creations

```javascript
factory.on("Created", (bondingCurve, token, pair, creator, event) => {
    console.log("New token created!");
    console.log("Token:", token);
    console.log("BondingCurve:", bondingCurve);
    console.log("Creator:", creator);
});
```

### Listen for All Trades

```javascript
factory.on("Buy", (bc, token, buyer, amountIn, amountOut) => {
    console.log(`Buy on ${token}: ${ethers.utils.formatEther(amountIn)} BNB → ${ethers.utils.formatEther(amountOut)} tokens`);
});

factory.on("Sell", (bc, token, seller, amountIn, amountOut) => {
    console.log(`Sell on ${token}: ${ethers.utils.formatEther(amountIn)} tokens → ${ethers.utils.formatEther(amountOut)} BNB`);
});
```

### Check if Address is a Bullshot Bonding Curve

```javascript
const isBondingCurve = await factory.isBondingCurveAddress("0x...");
if (isBondingCurve) {
    console.log("This address is a Bullshot BondingCurve");
}
```

---

## Important Notes

1. **Fee Denominator**: All fee percentages use `FEE_DENOMINATOR = 1000`. So `buyFeePercent = 10` means 1%.
2. **Creation Fee**: `creationFeeAmount` is in wei and transferred to `feeRecipient` before the bonding curve is initialized.
3. **Clone Pattern**: Both BondingCurve and BCToken are deployed as ERC1167 minimal proxies pointing to master implementations — this makes token creation extremely gas-efficient.
4. **Pair Address at Creation**: The `pair` field in the `Created` event is always `address(0)`. The actual PancakeSwap pair is created lazily on the first buy call.
5. **Only BondingCurves Can Emit**: `emitBuyEvent` and `emitSellEvent` can only be called by registered bonding curve addresses (`isBondingCurveAddress[msg.sender] == true`).
