Skip to content

Commit

Permalink
Merge branch 'dev' into all-contributors/add-EjembiEmmanuel
Browse files Browse the repository at this point in the history
  • Loading branch information
akiraonstarknet authored Jun 1, 2024
2 parents 45932d2 + 9271d78 commit 685a5aa
Show file tree
Hide file tree
Showing 3 changed files with 343 additions and 0 deletions.
9 changes: 9 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,15 @@
"contributions": [
"code",
"doc"
],
},
{
"login": "kateberryd",
"name": "Catherine Jonathan",
"avatar_url": "https://avatars.githubusercontent.com/u/35270183?v=4",
"profile": "https://github.com/kateberryd",
"contributions": [
"code"
]
}
]
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ Thanks goes to these wonderful people.
<td align="center" valign="top" width="14.28%"><a href="https://github.com/raizo07"><img src="https://avatars.githubusercontent.com/u/81079370?v=4?s=100" width="100px;" alt="Wolf"/><br /><sub><b>Wolf</b></sub></a><br /><a href="#infra-raizo07" title="Infrastructure (Hosting, Build-Tools, etc)">🚇</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/jedstroke"><img src="https://avatars.githubusercontent.com/u/86930056?v=4?s=100" width="100px;" alt="Jed"/><br /><sub><b>Jed</b></sub></a><br /><a href="#code-jedstroke" title="Code">💻</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/EjembiEmmanuel"><img src="https://avatars.githubusercontent.com/u/83036156?v=4?s=100" width="100px;" alt="Emmaunuel Ejembi"/><br /><sub><b>Emmaunuel Ejembi</b></sub></a><br /><a href="#code-EjembiEmmanuel" title="Code">💻</a> <a href="#doc-EjembiEmmanuel" title="Documentation">📖</a></td>
<td align="center" valign="top" width="14.28%"><a href="https://github.com/kateberryd"><img src="https://avatars.githubusercontent.com/u/35270183?v=4?s=100" width="100px;" alt="Catherine Jonathan"/><br /><sub><b>Catherine Jonathan</b></sub></a><br /><a href="#code-kateberryd" title="Code">💻</a></td>
</tr>
</tbody>
</table>
Expand Down
333 changes: 333 additions & 0 deletions docs/add_new_protocol.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,333 @@
# Add New Protocol

This documentation provides a guide on how to create a store for a protocol, which implements the IDapp class from `IDapp.store.ts`. The store fetches, processes, and manages APR and pool data for a specific decentralized application (dApp).

## Prerequisites

Before starting, ensure you have the following:

- A basic understanding of TypeScript and object-oriented programming.
- Familiarity with React and state management using Jotai.
- Knowledge of how to fetch and handle data from APIs.

## Steps to Create a Store

1. Define the Protocol Class

Create a new file for your protocol, e.g., `myprotocol.store.ts` in `src/store`. Import necessary modules and extend the IDapp class.

```TypeScript
'use client';

import CONSTANTS, { TOKENS, TokenName } from '@/constants';
import {
APRSplit,
Category,
PoolInfo,
PoolMetadata,
PoolType,
ProtocolAtoms,
} from './pools';
import { atom } from 'jotai';
import { AtomWithQueryResult, atomWithQuery } from 'jotai-tanstack-query';
import { TokenInfo } from '@/strategies/IStrategy';
import { IDapp } from './IDapp.store';
const fetcher = (...args: any[]) => {
return fetch(args[0], args[1]).then((res) => res.json());
};

const POOL_NAMES: string[] = ['STRK/USDC', 'STRK/ETH', 'ETH/USDC', 'USDC/USDT'];

export class MyProtocol extends IDapp<BaseAPYT> {}
```

2. Implement Function to Compute Pools Info

Add a method to compute pool information within your protocol class.

```TypeScript
export class MyProtocol extends IDapp<BaseAPYT> {
_computePoolsInfo(data: any) {
try {
const myData = data[this.incentiveDataKey];
if (!myData) return [];
const pools: PoolInfo[] = [];

Object.keys(myData)
.filter(this.commonVaultFilter)
.forEach((poolName) => {
const arr = myData[poolName];
let category = Category.Others;
if (poolName === 'USDC/USDT') {
category = Category.Stable;
} else if (poolName.includes('STRK')) {
category = Category.STRK;
}

const tokens: TokenName[] = poolName.split('/');
const logo1 = CONSTANTS.LOGOS[tokens[0]];
const logo2 = CONSTANTS.LOGOS[tokens[1]];

const poolInfo: PoolInfo = {
pool: {
name: poolName,
logos: [logo1, logo2],
},
protocol: {
name: this.name,
link: this.link,
logo: this.logo,
},
apr: arr[arr.length - 1].apr,
tvl: arr[arr.length - 1].tvl_usd,
aprSplits: [
{
apr: arr[arr.length - 1].apr,
title: 'STRK rewards',
description: 'Starknet DeFi Spring incentives',
},
],
category,
type: PoolType.DEXV3,
lending: {
collateralFactor: 0,
},
borrow: {
borrowFactor: 0,
apr: 0,
},
};
pools.push(poolInfo);
});

return pools;
} catch (err) {
throw err;
}
}

commonVaultFilter(poolName: string) {
const supportedPools = [
'ETH/USDC',
'STRK/USDC',
'STRK/ETH',
'USDC/USDT',
'USDC',
'USDT',
'ETH',
'STRK',
];
return supportedPools.includes(poolName);
}
}
```

3. Implement Function to Calculate Base APRs

Add a method to calculate the base APRs.

```TypeScript
export class MyProtocol extends IDapp<BaseAPYT> {
// previous code ...

getBaseAPY(p: PoolInfo, data: AtomWithQueryResult<BaseAPYT, Error>) {
// logic to calculate the base APRs for the pools in the protocol you're adding goes here.

// base APR is calculated by:
const baseAPR = 365 * ((fees0 + fees1) / (tvl0 + tvl1));

/**
* where:
* fees0 = fees for base token
* fees1 = fees for quote token
* tvl0 = total volume locked for base token
* tvl1 = total volume locked for quote token
*/


// see getBaseAPY() IDapp.store.ts for how the data is returned.
}
}
```

4. Instantiate Protocol class

```TypeScript
export const myProtocol = new MyProtocol();
```

5. Set Up Jotai Atoms

Set up Jotai atoms to manage the state and data fetching for the protocol.

```TypeScript
const MyProtocolAtoms: ProtocolAtoms = {
baseAPRs: atomWithQuery((get) => ({
queryKey: ['myprotocol_base_aprs'],
queryFn: async ({ queryKey }) => {
// logic to fetch pools data from the protocol's APIs goes here
// These data is used to calculate the base APRs for the pools
})),
pools: atom((get) => {
const poolsInfo = get(StrkDexIncentivesAtom);
const empty: PoolInfo[] = [];
if (!MyProtocolAtoms.baseAPRs) return empty;
const baseInfo = get(MyProtocolAtoms.baseAPRs);
if (poolsInfo.data) {
const pools = myProtocol._computePoolsInfo(poolsInfo.data);
return myProtocol.addBaseAPYs(pools, baseInfo);
}
return empty;
}),
};
```
5. Export Protocol Atoms
```TypeScript
export default MyProtocolAtoms;
```
## Complete code
```TypeScript
'use client';

import CONSTANTS, { TOKENS, TokenName } from '@/constants';
import {
APRSplit,
Category,
PoolInfo,
PoolMetadata,
PoolType,
ProtocolAtoms,
} from './pools';
import { atom } from 'jotai';
import { AtomWithQueryResult, atomWithQuery } from 'jotai-tanstack-query';
import { TokenInfo } from '@/strategies/IStrategy';
import { IDapp } from './IDapp.store';
const fetcher = (...args: any[]) => {
return fetch(args[0], args[1]).then((res) => res.json());
};

const POOL_NAMES: string[] = ['STRK/USDC', 'STRK/ETH', 'ETH/USDC', 'USDC/USDT'];

export class MyProtocol extends IDapp<BaseAPYT> {
_computePoolsInfo(data: any) {
try {
const myData = data[this.incentiveDataKey];
if (!myData) return [];
const pools: PoolInfo[] = [];

Object.keys(myData)
.filter(this.commonVaultFilter)
.forEach((poolName) => {
const arr = myData[poolName];
let category = Category.Others;
if (poolName === 'USDC/USDT') {
category = Category.Stable;
} else if (poolName.includes('STRK')) {
category = Category.STRK;
}

const tokens: TokenName[] = poolName.split('/');
const logo1 = CONSTANTS.LOGOS[tokens[0]];
const logo2 = CONSTANTS.LOGOS[tokens[1]];

const poolInfo: PoolInfo = {
pool: {
name: poolName,
logos: [logo1, logo2],
},
protocol: {
name: this.name,
link: this.link,
logo: this.logo,
},
apr: arr[arr.length - 1].apr,
tvl: arr[arr.length - 1].tvl_usd,
aprSplits: [
{
apr: arr[arr.length - 1].apr,
title: 'STRK rewards',
description: 'Starknet DeFi Spring incentives',
},
],
category,
type: PoolType.DEXV3,
lending: {
collateralFactor: 0,
},
borrow: {
borrowFactor: 0,
apr: 0,
},
};
pools.push(poolInfo);
});

return pools;
} catch (err) {
throw err;
}
}

commonVaultFilter(poolName: string) {
const supportedPools = [
'ETH/USDC',
'STRK/USDC',
'STRK/ETH',
'USDC/USDT',
'USDC',
'USDT',
'ETH',
'STRK',
];
return supportedPools.includes(poolName);
}

getBaseAPY(p: PoolInfo, data: AtomWithQueryResult<BaseAPYT, Error>) {
}
}

export const myProtocol = new MyProtocol();

const MyProtocolAtoms: ProtocolAtoms = {
baseAPRs: atomWithQuery((get) => ({
queryKey: ['myprotocol_base_aprs'],
queryFn: async ({ queryKey }) => {
})),
pools: atom((get) => {
const poolsInfo = get(StrkDexIncentivesAtom);
const empty: PoolInfo[] = [];
if (!MyProtocolAtoms.baseAPRs) return empty;
const baseInfo = get(MyProtocolAtoms.baseAPRs);
if (poolsInfo.data) {
const pools = myProtocol._computePoolsInfo(poolsInfo.data);
return myProtocol.addBaseAPYs(pools, baseInfo);
}
return empty;
}),
};

export default MyProtocolAtoms;
```
6. Import Protocol in `src/store/pools.ts`
```TypeScript
import MyProtocolAtoms, { myProtocol } from './myprotocol.store';
```
7. Add Protocol to `PROTOCOLS` array `src/store/pools.ts`
```TypeScript
export const PROTOCOLS = [
// other protocols...
{
name: myprotocol.name,
class: myprotocol,
atoms: MyProtocolAtoms,
}
]
```

0 comments on commit 685a5aa

Please sign in to comment.