Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,5 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*

/src/typechain/
10 changes: 8 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"@fortawesome/free-regular-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.16",
"@reduxjs/toolkit": "^1.7.1",
"@testing-library/jest-dom": "^5.11.4",
"@testing-library/react": "^11.1.0",
"@testing-library/user-event": "^12.1.10",
Expand Down Expand Up @@ -42,6 +43,7 @@
"react-bootstrap": "^2.0.3",
"react-dom": "^17.0.2",
"react-helmet": "^6.1.0",
"react-redux": "^7.2.6",
"react-router-dom": "^6.0.2",
"react-scripts": "4.0.3",
"react-toastify": "^8.1.0",
Expand All @@ -52,7 +54,9 @@
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
"eject": "react-scripts eject",
"typechain:build": "yarn run typechain --target ethers-v5 --out-dir src/typechain src/contracts/abis/*.json",
"postinstall": "yarn typechain:build"
},
"eslintConfig": {
"extends": [
Expand All @@ -73,12 +77,14 @@
]
},
"devDependencies": {
"@typechain/ethers-v5": "^8.0.5",
"@typescript-eslint/eslint-plugin": "4.0.1",
"@typescript-eslint/parser": "4.0.1",
"eslint-config-airbnb": "^19.0.2",
"eslint-plugin-import": "^2.25.3",
"eslint-plugin-jsx-a11y": "^6.5.1",
"eslint-plugin-react": "^7.27.1",
"eslint-plugin-react-hooks": "^4.3.0"
"eslint-plugin-react-hooks": "^4.3.0",
"typechain": "^6.1.0"
}
}
29 changes: 27 additions & 2 deletions src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
import React from "react";
import React, { useEffect } from "react";
import {
BrowserRouter as Router,
Routes,
Route
} from "react-router-dom";
import { useWeb3React } from "@web3-react/core";
import { StaticJsonRpcProvider, Web3Provider } from "@ethersproject/providers";

import { library } from "@fortawesome/fontawesome-svg-core";
import { fas } from "@fortawesome/free-solid-svg-icons";
import { ToastContainer } from "react-toastify";
import { loadApp } from "./state/appState";
import { loadAccount } from "./state/accountState";
import "./assets/scss/styles.scss";
import "react-toastify/dist/ReactToastify.css";

Expand All @@ -16,13 +21,33 @@ import Swap from "./pages/Swap";
import Farm from "./pages/Farm";
import useEagerConnect from "./hooks/useEagerConnect";
import Bootstrap from "./pages/Bootstrap/Bootstrap";
import { ToastContainer } from "react-toastify";
import { useDispatch } from "react-redux";

// add fontawesome icons
library.add(fas);

export default function App(): JSX.Element {
useEagerConnect();
const dispatch = useDispatch();
const { chainId, account, active, library } = useWeb3React();

useEffect( () => {
if (!chainId) return;
if (!library) return;
const castedLibrary = library as Web3Provider;;

dispatch(loadApp({ chainId , provider: castedLibrary }));
}, []);


useEffect( () => {
if (!chainId) return;
if (!account) return;
if (!active) return;
const castedLibrary = library as Web3Provider;;

dispatch(loadAccount({ chainId, provider: castedLibrary, account }));
}, [active]);

return (
<>
Expand Down
8 changes: 7 additions & 1 deletion src/Providers.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import React from "react";
import { Web3ReactProvider } from "@web3-react/core";
import { Provider } from "react-redux";
import { Web3Provider } from "@ethersproject/providers";
import { POLLING_INTERVAL } from "./constants/connectors";
import store from "./state/store";

// eslint-disable-next-line @typescript-eslint/no-explicit-any
function getLibrary(provider: any): Web3Provider {
Expand All @@ -17,7 +19,11 @@ interface Props {
export default function Providers(props: Props): JSX.Element {
return (
<>
<Web3ReactProvider getLibrary={getLibrary}>{props?.children}</Web3ReactProvider>
<Web3ReactProvider getLibrary={getLibrary}>
<Provider store={store}>
{props?.children}
</Provider>
</Web3ReactProvider>
</>
);
}
11 changes: 9 additions & 2 deletions src/components/TokenAmountInput/TokenAmountInput.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from "react";
import { TokenData } from "../../interfaces/TokenData";
import { BigNumber } from "ethers";
import { BigNumber, ethers } from "ethers";
import { Dropdown, DropdownButton } from "react-bootstrap";
import { Token } from "@uniswap/sdk";
import TOKENS from "../../data/tokens";
Expand All @@ -18,6 +18,13 @@ export default function TokenAmountInput(props: Props): JSX.Element {
// TODO: Move to a token list
const tokens = TOKENS;

const balance = token?.balance;
let displayVal = "0";
if (balance) {
displayVal = ethers.utils.formatEther(balance);
}
console.log(displayVal);

return (
<>
<div className="token-amount form-group">
Expand Down Expand Up @@ -70,7 +77,7 @@ export default function TokenAmountInput(props: Props): JSX.Element {
amount: token?.balance
}
})}
>Max: {token.balance.toString()} {token.token?.symbol || ""}</span>
>Max: {displayVal} {token.token?.symbol || ""}</span>
</p>
)}
</div>
Expand Down
4 changes: 3 additions & 1 deletion src/constants/contracts.ts → src/contracts/contracts.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { SupportedChainId } from "./chains";
import { SupportedChainId } from "../constants/chains";
import { abi as gOHMAbi } from "./abis/gOHM.json";

export const tokens = {
gOHM: {
[SupportedChainId.MAINNET]: "0x0ab87046fBb341D058F17CBC4c1133F25a20a52f",
[SupportedChainId.RINKEBY]: "0x70699eae51C0068917dE7Ce689C2dC3b2B074C1F",
abi: gOHMAbi
},
};

Expand Down
3 changes: 1 addition & 2 deletions src/data/tokens.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import { Token } from "@uniswap/sdk";

const TOKENS: Token[] = [
new Token(1, "0x000000000000000000000000000000000000fafa", 18, "OHM", "OlympusDAO"),
new Token(1, "0x000000000000000000000000000000000000faaf", 18, "WETH", "Wrapped Ether"),
new Token(1, "0x0ab87046fBb341D058F17CBC4c1133F25a20a52f", 18, "gOHM", "Governance OHM"), // TODO(zx): This is duped in contracts/
];

export default TOKENS;
6 changes: 6 additions & 0 deletions src/hooks/stateHooks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@

import { TypedUseSelectorHook, useDispatch, useSelector } from "react-redux";
import { AppDispatch, RootState } from "../state/store";

export const useAppSelector: TypedUseSelectorHook<RootState> = useSelector;
export const useAppDispatch = () => useDispatch<AppDispatch>();
2 changes: 1 addition & 1 deletion src/interfaces/TokenData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ export interface TokenData {
token?: Token,
balance?: BigNumber,
allowance?: BigNumber,
amount?: BigNumber
amount?: BigNumber // What is this?
}
17 changes: 15 additions & 2 deletions src/pages/Bootstrap/Bootstrap.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import React, { useState } from "react";
import React, { useEffect, useState } from "react";
import { BigNumber } from "ethers";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { Modal } from "react-bootstrap";
import { toast } from "react-toastify";
import TokenAmountInput from "../../components/TokenAmountInput/TokenAmountInput";
import { TokenData } from "../../interfaces/TokenData";
import { toast } from "react-toastify";
import { useAppSelector } from "../../hooks/stateHooks";
import TOKENS from "../../data/tokens";


export default function Bootstrap(): JSX.Element {
// states
const [inputToken, setInputToken] = useState<TokenData | null>(null);
const [showSwapSettingsModal, setShowSwapSettingsModal] = useState<boolean>(false);

const gohmBalance = useAppSelector(state => {
return state.account.tokens && state.account.tokens.gohm;
});

const approve = async () => {
toast("Please confirm transaction");
console.log("...");
Expand All @@ -20,6 +28,11 @@ export default function Bootstrap(): JSX.Element {
console.log("...");
};

useEffect(()=>{
// TODO(zx): data is split consolidate pls.
setInputToken({ token: TOKENS[0], balance: gohmBalance, allowance: BigNumber.from(420) });
}, [gohmBalance]);

return (
<>
<div className="row justify-content-center">
Expand Down
76 changes: 76 additions & 0 deletions src/state/accountState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import { EtherscanProvider, JsonRpcProvider, StaticJsonRpcProvider, Web3Provider } from "@ethersproject/providers";
import { createSlice, createSelector, createAsyncThunk } from "@reduxjs/toolkit";
import { BigNumber, ethers } from "ethers";
import { SupportedChainId } from "../constants/chains";
import { RootState } from "./store";
import { tokens } from "../contracts/contracts";
import { GOHM } from "../typechain";
Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I realized that we don't need gohm specific ABIs. I will change this to be a standard ERC20 ABI.




interface IAsyncThunk {
readonly chainId: SupportedChainId;
readonly provider: Web3Provider;
readonly account: string;
}

// TODO (zx): Fix discrepency between This, interfaces/TokenData, contracts/contracts, data/tokens
interface ITokenData {
[key: string]: BigNumber
}

export interface IAccountData {
readonly loading: boolean;
readonly tokens?: ITokenData;
}

const initialState: IAccountData = {
loading: false
};


export const loadAccount = createAsyncThunk(
"account/loadAccount",
async ({ chainId, provider, account }: IAsyncThunk) => {
console.log("getting account data");

const gOhmContract = new ethers.Contract(tokens.gOHM[chainId], tokens.gOHM.abi, provider) as GOHM;
const gOHMBalance = await gOhmContract.balanceOf(account);

return { tokens: { "gohm": gOHMBalance } };
},
);


const accountSlice = createSlice({
name: "account",
initialState,
reducers: {
fetchAccountSuccess(state, action) {
console.log("Account SUCCESS!, what do i do here? ");
},
},
extraReducers: builder => {
builder
.addCase(loadAccount.pending, state => {
state.loading = true;
})
.addCase(loadAccount.fulfilled, (state, action) => {
state.tokens = action.payload.tokens;
state.loading = false;
})
.addCase(loadAccount.rejected, (state, { error }) => {
state.loading = false;
console.error(error.name, error.message, error.stack);
});

},
});


const baseInfo = (state: RootState) => state.account;
export const getAccountState = createSelector(baseInfo, account => account);
export const { reducer } = accountSlice;
export const { fetchAccountSuccess } = accountSlice.actions;


65 changes: 65 additions & 0 deletions src/state/appState.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { JsonRpcProvider, StaticJsonRpcProvider, Web3Provider } from "@ethersproject/providers";
import { createSlice, createSelector, createAsyncThunk } from "@reduxjs/toolkit";
import { SupportedChainId } from "../constants/chains";
import { RootState } from "./store";


export interface IAsyncThunk {
readonly chainId: SupportedChainId;
readonly provider: Web3Provider;
}

export interface IAppData {
readonly loading: boolean;
readonly farms?: string[];
}



export const loadApp = createAsyncThunk(
"app/loadApp",
async ({ chainId, provider }: IAsyncThunk) => {
console.log(chainId, provider, "Loading App Data");
return { farms: [] };
},
);


const initialState: IAppData = {
loading: false,
};

const appSlice = createSlice({
name: "app",
initialState,
reducers: {
fetchAppSuccess(state, action) {
console.log("SUCCESS!, what do i do here? ");
},
},
extraReducers: builder => {
builder
.addCase(loadApp.pending, state => {
state.loading = true;
})
.addCase(loadApp.fulfilled, (state, action) => {
state.farms = action.payload.farms;
state.loading = false;
})
.addCase(loadApp.rejected, (state, { error }) => {
state.loading = false;
console.error(error.name, error.message, error.stack);
});
},
});




const baseInfo = (state: RootState) => state.app;
export const getAppState = createSelector(baseInfo, app => app);

export const { reducer } = appSlice;
export const { fetchAppSuccess } = appSlice.actions;


Loading