diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..49729e9
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,12 @@
+FROM ruby:2.7.4
+
+RUN apt update && apt install -y graphviz nodejs npm
+RUN npm i -g yarn
+
+WORKDIR /usr/src/app
+USER 1000:1000
+COPY Gemfile Gemfile.lock /usr/src/app/
+RUN bundle install
+
+COPY . /usr/src/app
+CMD bundle exec rails s -b 0.0.0.0
\ No newline at end of file
diff --git a/app/javascript/src/abi/erc20.json b/app/javascript/src/abi/erc20.json
new file mode 100644
index 0000000..3b0ab2f
--- /dev/null
+++ b/app/javascript/src/abi/erc20.json
@@ -0,0 +1,222 @@
+[
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "name",
+ "outputs": [
+ {
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_spender",
+ "type": "address"
+ },
+ {
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "approve",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "totalSupply",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_from",
+ "type": "address"
+ },
+ {
+ "name": "_to",
+ "type": "address"
+ },
+ {
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "transferFrom",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "decimals",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint8"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "_owner",
+ "type": "address"
+ }
+ ],
+ "name": "balanceOf",
+ "outputs": [
+ {
+ "name": "balance",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [],
+ "name": "symbol",
+ "outputs": [
+ {
+ "name": "",
+ "type": "string"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "constant": false,
+ "inputs": [
+ {
+ "name": "_to",
+ "type": "address"
+ },
+ {
+ "name": "_value",
+ "type": "uint256"
+ }
+ ],
+ "name": "transfer",
+ "outputs": [
+ {
+ "name": "",
+ "type": "bool"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "nonpayable",
+ "type": "function"
+ },
+ {
+ "constant": true,
+ "inputs": [
+ {
+ "name": "_owner",
+ "type": "address"
+ },
+ {
+ "name": "_spender",
+ "type": "address"
+ }
+ ],
+ "name": "allowance",
+ "outputs": [
+ {
+ "name": "",
+ "type": "uint256"
+ }
+ ],
+ "payable": false,
+ "stateMutability": "view",
+ "type": "function"
+ },
+ {
+ "payable": true,
+ "stateMutability": "payable",
+ "type": "fallback"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "owner",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "spender",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Approval",
+ "type": "event"
+ },
+ {
+ "anonymous": false,
+ "inputs": [
+ {
+ "indexed": true,
+ "name": "from",
+ "type": "address"
+ },
+ {
+ "indexed": true,
+ "name": "to",
+ "type": "address"
+ },
+ {
+ "indexed": false,
+ "name": "value",
+ "type": "uint256"
+ }
+ ],
+ "name": "Transfer",
+ "type": "event"
+ }
+]
\ No newline at end of file
diff --git a/app/javascript/src/abi/pancake-router-v2.json b/app/javascript/src/abi/pancake-router-v2.json
new file mode 100644
index 0000000..383ca61
--- /dev/null
+++ b/app/javascript/src/abi/pancake-router-v2.json
@@ -0,0 +1 @@
+[{"inputs":[{"internalType":"address","name":"_factory","type":"address"},{"internalType":"address","name":"_WETH","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"WETH","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"amountADesired","type":"uint256"},{"internalType":"uint256","name":"amountBDesired","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amountTokenDesired","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"addLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"},{"internalType":"uint256","name":"liquidity","type":"uint256"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"factory","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountIn","outputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"reserveIn","type":"uint256"},{"internalType":"uint256","name":"reserveOut","type":"uint256"}],"name":"getAmountOut","outputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsIn","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"}],"name":"getAmountsOut","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"reserveA","type":"uint256"},{"internalType":"uint256","name":"reserveB","type":"uint256"}],"name":"quote","outputs":[{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidity","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETH","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"removeLiquidityETHSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermit","outputs":[{"internalType":"uint256","name":"amountToken","type":"uint256"},{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountTokenMin","type":"uint256"},{"internalType":"uint256","name":"amountETHMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityETHWithPermitSupportingFeeOnTransferTokens","outputs":[{"internalType":"uint256","name":"amountETH","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"tokenA","type":"address"},{"internalType":"address","name":"tokenB","type":"address"},{"internalType":"uint256","name":"liquidity","type":"uint256"},{"internalType":"uint256","name":"amountAMin","type":"uint256"},{"internalType":"uint256","name":"amountBMin","type":"uint256"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"bool","name":"approveMax","type":"bool"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"removeLiquidityWithPermit","outputs":[{"internalType":"uint256","name":"amountA","type":"uint256"},{"internalType":"uint256","name":"amountB","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapETHForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactETHForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForETHSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountIn","type":"uint256"},{"internalType":"uint256","name":"amountOutMin","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapExactTokensForTokensSupportingFeeOnTransferTokens","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactETH","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amountOut","type":"uint256"},{"internalType":"uint256","name":"amountInMax","type":"uint256"},{"internalType":"address[]","name":"path","type":"address[]"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"deadline","type":"uint256"}],"name":"swapTokensForExactTokens","outputs":[{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]
\ No newline at end of file
diff --git a/app/javascript/src/components/Poo.tsx b/app/javascript/src/components/Poo.tsx
new file mode 100644
index 0000000..5e3bbd9
--- /dev/null
+++ b/app/javascript/src/components/Poo.tsx
@@ -0,0 +1,98 @@
+import React from "react";
+import BigNumber from "bignumber.js";
+
+import type { PoolConfig } from "../types";
+import { useBsc } from "../contexts/BscProvider";
+import { getPriceInBusd } from "../utils/getPrice";
+import { getApr } from "../utils/apr";
+import { getTotalStaked } from "../utils/getTotalStaked";
+
+type PoolProps = {
+ pool: PoolConfig;
+};
+
+export const Pool = ({ pool }: PoolProps) => {
+ const {
+ provider,
+ pancake: { router },
+ } = useBsc();
+
+ const [apr, setApr] = React.useState<{
+ value: string | null;
+ loading: boolean;
+ }>({
+ value: null,
+ loading: true,
+ });
+
+ React.useEffect(() => {
+ (async () => {
+ const stakingPrice = await getPriceInBusd(router, pool.stakingToken);
+ const earningPrice = await getPriceInBusd(router, pool.earningToken);
+
+ const totalStaked = await getTotalStaked(provider, pool);
+
+ console.log(
+ `Total Staked for ${pool.stakingToken.symbol} - ${
+ pool.earningToken.symbol
+ }: ${JSON.stringify(totalStaked)}`
+ );
+
+ const aprValue = getApr(
+ stakingPrice,
+ earningPrice,
+ totalStaked,
+ parseFloat(pool.tokenPerBlock) / 1e-18
+ );
+
+ if (aprValue) {
+ setApr({
+ loading: false,
+ value: aprValue.toFixed(2),
+ });
+ }
+ })();
+ }, []);
+
+ return (
+
+
+

+
+
+ Investir:{" "}
+ {pool.stakingToken.symbol}
+
+
+ Receber:{" "}
+ {pool.earningToken.symbol}
+
+
+
Rendimento:
+ {apr.loading ? (
+
+ ) : (
+ `${apr.value}%`
+ )}
+
+
+
+ );
+};
\ No newline at end of file
diff --git a/app/javascript/src/components/PoolListing.tsx b/app/javascript/src/components/PoolListing.tsx
index b44c66a..1a98646 100644
--- a/app/javascript/src/components/PoolListing.tsx
+++ b/app/javascript/src/components/PoolListing.tsx
@@ -1,6 +1,7 @@
import React from "react";
import { pools } from "../constants/Pools";
+import { Pool } from "./Poo";
export const PoolListing = () => {
return (
@@ -8,43 +9,7 @@ export const PoolListing = () => {
{pools
.filter((pool) => !pool.isFinished)
.sort((a, b) => (a.sortOrder ?? 0) - (b.sortOrder ?? 0))
- .map((pool) => (
-
-
-

-
-
- Investir:{" "}
- {pool.stakingToken.symbol}
-
-
- Receber:{" "}
- {pool.earningToken.symbol}
-
-
-
-
- ))}
+ .map((pool) => )}
);
};
diff --git a/app/javascript/src/constants/index.ts b/app/javascript/src/constants/index.ts
new file mode 100644
index 0000000..919384c
--- /dev/null
+++ b/app/javascript/src/constants/index.ts
@@ -0,0 +1,6 @@
+import BigNumber from "bignumber.js";
+
+export const BSC_BLOCK_TIME = 3;
+export const BLOCKS_PER_YEAR = new BigNumber(
+ (60 / BSC_BLOCK_TIME) * 60 * 24 * 365
+);
\ No newline at end of file
diff --git a/app/javascript/src/contexts/BscProvider.tsx b/app/javascript/src/contexts/BscProvider.tsx
new file mode 100644
index 0000000..5f84e23
--- /dev/null
+++ b/app/javascript/src/contexts/BscProvider.tsx
@@ -0,0 +1,49 @@
+import React, { useContext } from "react";
+import { ethers } from "ethers";
+
+import pancakeRouterV2 from "../abi/pancake-router-v2.json";
+
+const provider = new ethers.providers.JsonRpcProvider(
+ "https://bsc-dataseed1.defibit.io/\n"
+);
+
+const router = new ethers.Contract(
+ "0x10ED43C718714eb63d5aA57B78B54704E256024E",
+ new ethers.utils.Interface(pancakeRouterV2),
+ provider
+);
+
+export type BscContext = {
+ provider: typeof provider;
+ pancake: {
+ router: InstanceType;
+ };
+};
+
+const Context = React.createContext({
+ provider,
+ pancake: {
+ router,
+ },
+});
+
+export const useBsc = () => {
+ const context = useContext(Context);
+
+ if (!context) {
+ throw new Error("You must wrap the component with ");
+ }
+
+ return context;
+};
+
+export const BscProvider = ({ children }: React.PropsWithChildren) => {
+ const value: BscContext = {
+ provider,
+ pancake: {
+ router,
+ },
+ };
+
+ return {children};
+};
\ No newline at end of file
diff --git a/app/javascript/src/utils/apr.ts b/app/javascript/src/utils/apr.ts
new file mode 100644
index 0000000..deb55dc
--- /dev/null
+++ b/app/javascript/src/utils/apr.ts
@@ -0,0 +1,22 @@
+import BigNumber from "bignumber.js";
+
+import { BLOCKS_PER_YEAR } from "../constants";
+
+export const getApr = (
+ stakingTokenPrice: number,
+ rewardTokenPrice: number,
+ totalStaked: number,
+ tokenPerBlock: number
+) => {
+ const totalRewardPricePerYear = new BigNumber(rewardTokenPrice)
+ .times(tokenPerBlock)
+ .times(BLOCKS_PER_YEAR);
+
+ const totalStakingTokenInPool = new BigNumber(stakingTokenPrice).times(
+ totalStaked
+ );
+
+ const apr = totalRewardPricePerYear.div(totalStakingTokenInPool).times(100);
+
+ return apr.isNaN() || !apr.isFinite() ? null : apr.toNumber();
+};
\ No newline at end of file
diff --git a/app/javascript/src/utils/getPrice.ts b/app/javascript/src/utils/getPrice.ts
new file mode 100644
index 0000000..3676340
--- /dev/null
+++ b/app/javascript/src/utils/getPrice.ts
@@ -0,0 +1,21 @@
+import { ethers } from "ethers";
+
+import { tokens } from "../constants/pancake/Tokens";
+import type { Token } from "../constants/pancake/Tokens";
+import type { BscContext } from "../contexts/BscProvider";
+
+// 1 Wei = 1*10^18 Ether
+const ONE_BUSD_IN_WEI = ethers.utils.parseUnits("1", 18);
+
+export const getPriceInBusd = async (router: any, token: Token) => {
+ try {
+ const result = await router.getAmountsOut(ONE_BUSD_IN_WEI, [
+ token.address["56"],
+ tokens.busd.address["56"],
+ ]);
+
+ return result[1].toString() / 1e18;
+ } catch {
+ return 0;
+ }
+};
\ No newline at end of file
diff --git a/app/javascript/src/utils/getTotalStaked.ts b/app/javascript/src/utils/getTotalStaked.ts
new file mode 100644
index 0000000..427928f
--- /dev/null
+++ b/app/javascript/src/utils/getTotalStaked.ts
@@ -0,0 +1,30 @@
+import { ethers } from "ethers";
+import BigNumber from "bignumber.js";
+
+import erc20 from "../abi/erc20.json";
+import { Token } from "../constants/pancake/Tokens";
+import type { PoolConfig } from "../types";
+
+export const getTotalStaked = async (
+ provider: ethers.providers.Provider,
+ pool: PoolConfig
+) => {
+ if (pool.stakingToken.symbol === "BNB") {
+ // TODO: BNB
+ return 0;
+ }
+
+ const contract = new ethers.Contract(
+ pool.stakingToken.address["56"],
+ erc20,
+ provider
+ );
+
+ try {
+ const result = await contract.balanceOf(pool.contractAddress["56"]);
+
+ return new BigNumber(result.toJSON().hex).toNumber();
+ } catch {
+ return 0;
+ }
+};
\ No newline at end of file
diff --git a/docker-compose.yaml b/docker-compose.yaml
new file mode 100644
index 0000000..f3eefeb
--- /dev/null
+++ b/docker-compose.yaml
@@ -0,0 +1,23 @@
+version: "3"
+services:
+ web:
+ ports:
+ - "3000:3000"
+ environment:
+ - DATABASE_URL=postgres://postgres:postgres@db:5432/postgres
+ image: xstake
+ depends_on:
+ - db
+ volumes:
+ - ./:/usr/src/app/
+ db:
+ image: postgres
+ environment:
+ - POSTGRES_USER=postgres
+ - POSTGRES_PASSWORD=postgres
+ ports:
+ - "5432:5432"
+ volumes:
+ - "data:/var/lib/postgresql/data"
+volumes:
+ data:
diff --git a/erd.svg b/erd.svg
index 966f06c..129d7bd 100644
--- a/erd.svg
+++ b/erd.svg
@@ -1,178 +1,178 @@
-
-