# How FundingWorks works

Supporters mint a pass that holds what they paid, in ETH or USDC. It streams to the creator over months, and any supporter can burn their pass to take back what hasn't streamed yet.

## Support

Mint a pass at the campaign price. The pass holds what you paid and shows you backed the creator. It can't be sold or transferred unless the creator allows it.

### Minting

The mint stays open for the window the creator picked, and a capped campaign stops minting when it sells out. You can mint several passes in one transaction. A USDC campaign asks you to approve the amount first, then mint.

- **Allowlist.** A creator can keep the start of the mint for allowlisted wallets, one pass each, then open it to everyone. Or keep the whole mint allowlist only.

### What your pass holds

The upfront share leaves at mint. The rest stays in the pass: all of it until the stream starts, then less every second until the stream ends.

- **Transfers after the stream.** Passes can't be sent or sold while they're locked. A creator can have them unlock when the stream ends.

#### Is this an investment?

No. It's patronage, closer to Patreon than to a token sale. There may be no financial return. Your protection is the right to leave and take back what's left.

#### Can I sell my pass?

Not while it's locked. A creator can have passes unlock when the stream ends. The campaign terms say if they do.

#### Which network does it use?

Ethereum mainnet. You need ETH or USDC for the pass price, depending on the campaign, and ETH for gas.

## Stream

Once the mint closes, the creator starts the stream and the funds flow to them second by second. Campaigns run 3 to 12 months. The creator sets a share paid at mint, and the protocol's 3% comes out of it.

Where a pass's ETH goes. For a 0.1 ETH pass at 10% upfront.

- Protocol fee: 0.003 ETH (3%). Taken from the upfront share at mint.
- Creator at mint: 0.007 ETH (7%). Paid to the creator at mint.
- Streamed to the creator: 0.09 ETH (90%). Released second by second until the stream ends.

### When it runs

The end date is fixed when the campaign is created. The stream runs from the moment the creator starts it until that date, so a stream started later runs faster and still ends on time.

### Getting paid

The upfront share is paid with every mint. Streamed funds build up second by second: the creator can collect it at any time, and it's also paid out whenever a supporter exits.

- **Payout address.** The creator's share of the mint and the stream goes to the wallet that created the campaign, or to another address they choose.

#### Does the fee come on top of the price?

No. It comes out of the upfront share. At 10% upfront, 3% goes to the protocol and 7% to the creator.

## Exit

Burn your pass to take back what hasn't streamed yet. No one has to approve it. The later you leave, the less is left.

What a supporter gets back. For a 0.1 ETH pass at 10% upfront, burned a quarter of the way through the stream.

- Upfront: 0.01 ETH (10%). Paid at mint, fee included.
- Streamed so far: 0.0225 ETH (22.5%). Paid to the creator when the pass is burned.
- Back to you: 0.0675 ETH (67.5%). Sent to the supporter in the same transaction.

### When you can leave

Exits open when the stream starts and close when it ends. Burning your pass pays the creator what had streamed up to that second and sends you the rest. The upfront share isn't returned.

- **Remints.** With remints on, anyone can mint a burned pass again while the stream runs. Not available when each pass has its own metadata file.
- **Remint price.** The creator picks one. Full price: a remint costs the pass price, and the creator gets the upfront share plus what that pass had already streamed. What's left: it costs what the pass still holds plus the 3% protocol fee, and that amount keeps streaming to the creator.

#### What happens if a creator stops working?

Supporters can burn their passes and take back what hasn't streamed. Funding only keeps flowing while supporters choose to stay.

#### Can I leave before the stream starts?

No. Until the creator starts the stream, your funds stay locked in the pass. Exits open the moment it starts.

## Launch

Set a price, a supply and a stream length. Supporters see every term before they mint.

### What you set

- **Price and supply.** The price of one pass in ETH or USDC, and either a fixed number of passes or an open edition.
- **Stream length.** 3 to 12 months from the day the campaign is created.
- **Upfront.** 10% to 50% of each mint, paid right away. The protocol's 3% comes out of it.

Pass art, the payout address, the allowlist, remints and transfers sit under More options. Each is explained where it matters: Support, Stream, Exit and Pass art.

#### Who can launch a campaign?

Anyone. The contracts are permissionless and open source, and the factory keeps every campaign within its limits.

## Pass art

What each pass shows in wallets and marketplaces. One image is the same for every pass. An IPFS folder gives each pass its own file: pass 1 reads folder/1, pass 2 reads folder/2. A contract builds each pass's metadata itself, so it can change over time.

### Dynamic passes

A pass can change with the campaign. Point the campaign at a renderer contract and every pass's `tokenURI` comes from it, read live from the chain.

The renderer can read what each pass holds: `getRemainingLockedEth(tokenId)` is what hasn't streamed yet, `initialLockedPerToken` is where it started, and `vestingStartTime`, `vestingEndDate` and `vestingComplete` place it in the stream. `ownerOf(tokenId)` is the holder.

1. Deploy a contract with `tokenURI(uint256)` that returns the metadata, like the example below.
2. Pick Contract under Pass art when you create the campaign. Later, the owner or manager can change or remove it under Settings on the campaign page, which calls `setTokenRenderer`.
3. To go back to the IPFS metadata, call `setTokenRenderer` with the zero address.

```solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.21;

import {Base64} from "@openzeppelin/contracts/utils/Base64.sol";
import {Strings} from "@openzeppelin/contracts/utils/Strings.sol";

interface IFundingWorks {
    function initialLockedPerToken() external view returns (uint256);
    function getRemainingLockedEth(uint256 tokenId) external view returns (uint256);
}

/// Each pass fills up as its ETH streams to the creator.
contract StreamRenderer {
    using Strings for uint256;

    IFundingWorks public immutable campaign;

    constructor(IFundingWorks _campaign) {
        campaign = _campaign;
    }

    function tokenURI(uint256 tokenId) external view returns (string memory) {
        uint256 start = campaign.initialLockedPerToken();
        uint256 left = campaign.getRemainingLockedEth(tokenId);
        uint256 streamed = start == 0 ? 100 : 100 - (left * 100) / start;

        string memory svg = string.concat(
            "<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'>",
            "<rect width='100' height='100' fill='black'/>",
            "<rect y='", (100 - streamed).toString(), "' width='100' height='",
            streamed.toString(), "' fill='rgb(34,197,94)'/></svg>"
        );
        string memory json = string.concat(
            '{"name":"Pass #', tokenId.toString(),
            '","attributes":[{"trait_type":"Streamed","value":', streamed.toString(),
            '}],"image":"data:image/svg+xml;base64,', Base64.encode(bytes(svg)), '"}'
        );

        return string.concat("data:application/json;base64,", Base64.encode(bytes(json)));
    }
}
```

The campaign doesn't announce metadata changes, so marketplaces may show a cached image until they refresh.

## Contracts

A factory deploys each campaign within set limits on price, upfront share and length. Each campaign contract enforces its own mint, stream, exits and claims.

- FundingWorksFactory: `0xa696CEb37Dc35102c869fF255056627E6dec4f0C`. Deploys every campaign, within the protocol's limits. [Etherscan](https://etherscan.io/address/0xa696CEb37Dc35102c869fF255056627E6dec4f0C), [evm.now](https://evm.now/address/0xa696CEb37Dc35102c869fF255056627E6dec4f0C), [Source code](https://etherscan.io/address/0xa696CEb37Dc35102c869fF255056627E6dec4f0C#code)
- FundingWorks v1: `0x967040B0CF4Dae55E5a8CDbCB5834447e57a2f04`. A live campaign contract: TokenWorks S02. [Etherscan](https://etherscan.io/address/0x967040B0CF4Dae55E5a8CDbCB5834447e57a2f04), [evm.now](https://evm.now/address/0x967040B0CF4Dae55E5a8CDbCB5834447e57a2f04), [Source code](https://etherscan.io/address/0x967040B0CF4Dae55E5a8CDbCB5834447e57a2f04#code)
- Each campaign is its own contract, deployed by the factory. Its address is on the campaign page.
- These are the contracts live on funding.works today, the first version. Pass art contracts, payout addresses, remints, USDC campaigns and onchain updates come with the next one.
