> For the complete documentation index, see [llms.txt](https://docs.summer.fi/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.summer.fi/lazy-summer-protocol/governance/tip-streams.md).

# Tip Streams

Tip streams distribute a portion of vault fees among specific entities entitled to a share. The process mints additional shares as tips (collected in the **TipJar**), which slightly dilutes existing shares so, to remain sustainable, vault yield must outpace the fees distributed.

Fees are set **per vault** by governance rather than by a single protocol-wide rate. Many stablecoin vaults use a \~1% AUM fee, but rates vary by vault and can be changed by SIP (for example, the [fee on the EURC vault on Base](https://forum.summer.fi/t/sip1-2-1-reduce-protocol-fee-on-eurc-vault-base/765) was reduced by governance, and the Ethereum Mainnet ETH vault uses \~0.3%). Always confirm the current fee for a specific vault, as DAO-managed and indexed vaults may set their own parameters.

## How Tip Streams Work

In any vault, the fee is set at the vault level; tip streams define how that fee is divided\
among recipients via a configurable tip rate. Tips are collected in the TipJar. Rather than\
being taken directly from vault assets, tips are represented by newly minted shares added to\
the TipJar, increasing total shares and marginally reducing per-share value.

When tips are distributed, they are not taken directly from the vault’s assets. Instead, additional shares are minted to represent the tips. These newly minted shares are added to the TipJar. This increases the total number of shares in the vault, slightly reducing the value of each share since the same amount of assets is now split among a larger number of shares.

The 1% AUM fee ensures a steady and predictable source for tip distribution. This percentage is applied to the total assets managed by the vault, making the system straightforward and easy to calculate.

Note: The Ethereum Mainnet $ETH vault charges a 0.3% AUM fees, instead of the 1% for stablecoin vaults.

#### TipStream Management Functions

`addTipStream(TipStream memory tipStream)`

```solidity
function addTipStream(TipStream memory tipStream) external onlyGovernor returns (uint256 lockedUntilEpoch) {
    if (tipStream.recipient == address(0)) {
        revert InvalidTipStreamRecipient();
    }
    if (tipStreams[tipStream.recipient].recipient != address(0)) {
        revert TipStreamAlreadyExists(tipStream.recipient);
    }
    if (tipStream.lockedUntilEpoch > block.timestamp + MAX_ALLOWED_LOCKED_UNTIL_EPOCH) {
        revert TipStreamLockedForTooLong(tipStream.recipient);
    }
    _validateTipStreamAllocation(tipStream.allocation, toPercentage(0));

    tipStreams[tipStream.recipient] = tipStream;
    tipStreamRecipients.push(tipStream.recipient);

    emit TipStreamAdded(tipStream);

    return tipStream.lockedUntilEpoch;
}
```

#### Distribution Functions

`shake(address fleetCommander)`

```solidity
function _shake(address fleetCommander_) internal {
    if (!IHarborCommand(harborCommand()).activeFleetCommanders(fleetCommander_)) {
        revert InvalidFleetCommanderAddress();
    }

    IFleetCommander fleetCommander = IFleetCommander(fleetCommander_);
    uint256 shares = fleetCommander.balanceOf(address(this));
    
    if (shares == 0) return;

    uint256 withdrawnAssets = fleetCommander.redeem(
        Constants.MAX_UINT256,
        address(this),
        address(this)
    );

    if (withdrawnAssets == 0) return;

    IERC20 underlyingAsset = IERC20(fleetCommander.asset());
    uint256 totalDistributed = 0;
    Percentage totalAllocated = toPercentage(0);

    for (uint256 i = 0; i < tipStreamRecipients.length; i++) {
        address recipient = tipStreamRecipients[i];
        Percentage allocation = tipStreams[recipient].allocation;
        totalAllocated = totalAllocated + allocation;

        uint256 amount = (totalAllocated == PERCENTAGE_100) ? 
            withdrawnAssets - totalDistributed :
            withdrawnAssets.applyPercentage(allocation);

        if (amount > 0) {
            underlyingAsset.safeTransfer(recipient, amount);
            totalDistributed += amount;
        }
    }

    uint256 remaining = withdrawnAssets - totalDistributed;
    if (remaining > 0) {
        underlyingAsset.safeTransfer(treasury(), remaining);
    }
}
```

#### Query Functions

`getTotalAllocation()`

```solidity
function getTotalAllocation() public view returns (Percentage total) {
    total = toPercentage(0);
    for (uint256 i = 0; i < tipStreamRecipients.length; i++) {
        total = total + tipStreams[tipStreamRecipients[i]].allocation;
    }
}
```

The contract uses the OpenZeppelin SafeERC20 library for safe token transfers and includes comprehensive error handling for invalid operations.
