---
# System prepended metadata

title: Allo Starter Kit

---

# Allo Starter Kit
Duplo blocks lets you build faster than Lego because the pieces are larger and more opinionated. Lego is faster than building the pieces by hand.

There's still creativity involved to build what you envision. 

![image](https://hackmd.io/_uploads/B1J3DIGQR.png)
![image](https://hackmd.io/_uploads/Hy16v8MQ0.png)

## Goals



- A developer can create a custom funding platform within ~~a day~~ 30 minutes
- Shared language for how we build products internally at Gitcoin


Building concrete applications in parallel to the kit will help guide the requirements.

## Ideas for apps
- Qhoney - mobile microapp to create fund projects
- QuadraticLands - app to fund local regen projects (display projects on a map)

Are there differences in how rounds are created and managed?
Any ephemeral or eternal rounds?

This document sketches out ideas for components that are useful when building a token allocation and distribution platform. 


> This document is very much work in progress! 

## Components


### ApiProvider

React Provider component that handles the internals of fetching data from indexers. This needs to wrap the app so the hooks and components know how to call the API.

It should be flexible enough to easily swap out API calls.

- Gitcoin Indexer?
- EasyRF?

API can be overridden like this:

```tsx
<ApiProvider
  api={{
    rounds: (query) =>
      // Can even support non-GraphQL endpoints
      fetch(`https://indexer/api?limit=${query.limit}&skip=${query.skip}`)
        .then((r) => r.json())
        .then((rounds) => rounds.map(transformRound)), // If indexer returns different shape of data
    roundById: (id) => fetch(`...`).then(transformRound),
    projects: (query) => {},
    projectById: () => {},
    metrics: (query) => {},
    metricById: () => {},
    ballot: () => {},
    saveBallot: (ballot) =>
      fetch(`https://api/ballot`, {
        body: JSON.stringify(transformBallot(ballot)), // If API expects different shape of ballot
      }),

    createRound: () => {},
    updateRound: () => {},
    createProject: () => {},
    updateProject: () => {},
    applyRound: () => {},
  }}
>
  {/* App */}
</ApiProvider>
```

### ConnectWallet

- Connect wallet button
- Sign SIWE auth (persistant JWT session)
- Sign messages
- WagmiProvider

### DiscoverRounds

Hook to fetch data from any component

```tsx
const { data, isPending } = useRounds(query: RoundsQuery);

```

Ready-made component to render a grid of rounds

```tsx
<DiscoverRounds
  /*
    DiscoverRounds is a pre-made component that does most of the heavy lifting
    in fething and displaying rounds.

    It fetches the rounds based on a provided query (with sane defaults) and
    renders it (as a grid by default but easy to customize with own components).
    */
  query={{
    /*
      The query prop enables a powerful way to fetch data from the indexer.

      For example:
      - only rounds with these strategies (deployed contract address)
      - order by when they were created, newest first
      - with skip and take we can paginate the results and decide how many to show
      */
    where: { strategy: { in: ["0x...a", "0x...b"] } },
    orderBy: { createdAt: "desc" },
    skip: 0,
    take: 12,
  }}
  /*
      The renderItem function lets us change what component is rendered.

      For example:
        - Wrap the default RoundItem component in a link

      */
  renderItem={(round, Component) => (
    <Link href={`/rounds/${round.id}`} key={round.id}>
      <Component {...round} />
    </Link>
  )}
  /*
        Columns let us choose how to render the rounds.

        For example:
          - 1 column on phones
          - 2 columns on small to medium
          - 3 columns on medium to large
          - 4 columns on large and above

        We could also set it to [1] to render as list on all screens
      */
  columns={[1, 2, 3, 4]}
/>
```

### RoundDetails

```tsx
const { data, isPending } = useRoundById(id: string);
```

### DiscoverProjects

```tsx
const { data, isPending } = useProjects(query: ProjectsQuery);
```

### ProjectsDetails

```tsx
const { data, isPending } = useProjectsById(id: string);
```

### DiscoverMetrics

```tsx
const { data, isPending } = useMetrics(query: MetricsQuery);
```

### MetricDetails

```tsx
const { data, isPending } = useMetricById(id: string);
```

### BallotEditor

Should be possible to use for both types of ballots (`metric`, `project`)

> What are the UI diffs?

```tsx
const { data, isPending } = useBallot();
const { mutate, isPending } = useSaveBallot();

const { set, inc, dec, add, remove, reset, state } = useBallotEditor(ballot, {
  debounceRate,
  onUpdate,
});
```

### BallotMetricsEditor

```tsx

```

### RoundForm

Create and edit a round.

This would likely be split into several components.

Some of the configurations

- round details (name, description)
- round phases (start, applications, voting, results, distribution, ...)
- network, token, strategy
- admin accounts

### RoundAdminVoters

Allowed voters (if applicable)

### RoundAdminApplications

Received applications.

### RoundDistribution

Distribute tokens to recipients.

### ProjectForm

Create and edit a project

### ProjectApplicationForm

Apply to a round with a project

---

- allocation sidebar (metric)
- ballot editor (metric)
- discover projects
- project details
- allocation sidebar (project)
- ballot editor (project)
- ballot editor (budget)
- submit ballot
- ballot confirmation
