diff --git a/.all-contributorsrc b/.all-contributorsrc
index 430b9646..55a28028 100644
--- a/.all-contributorsrc
+++ b/.all-contributorsrc
@@ -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"
]
}
]
diff --git a/README.md b/README.md
index 28ae5af1..db9fe174 100644
--- a/README.md
+++ b/README.md
@@ -85,6 +85,7 @@ Thanks goes to these wonderful people.
Wolf 🚇 |
Jed 💻 |
Emmaunuel Ejembi 💻 📖 |
+ Catherine Jonathan 💻 |
diff --git a/docs/add_new_protocol.md b/docs/add_new_protocol.md
new file mode 100644
index 00000000..40cecd57
--- /dev/null
+++ b/docs/add_new_protocol.md
@@ -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 {}
+```
+
+2. Implement Function to Compute Pools Info
+
+Add a method to compute pool information within your protocol class.
+
+```TypeScript
+export class MyProtocol extends IDapp {
+ _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 {
+ // previous code ...
+
+ getBaseAPY(p: PoolInfo, data: AtomWithQueryResult) {
+ // 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 {
+ _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) {
+ }
+}
+
+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,
+ }
+]
+```