Skip to content

Commit 07e8546

Browse files
AlexNi245Dhaiwat10
andauthored
feat(hooks): add useTokenBalance (#69)
* added ustTokenBalance hook * added error handling * export useTokenBalance from /hooks directory * . change hasError to errorMsg . rename ERC20 to ERC20.json . change name of args of useTokenBalance.ts * . use constants in stories . use rinkeby instead of mainnet * change order of hook's return values * Refactor and fix useTokenBalance Co-authored-by: Dhaiwat Pandya <[email protected]>
1 parent 7aa80d4 commit 07e8546

File tree

6 files changed

+317
-1
lines changed

6 files changed

+317
-1
lines changed
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
[
2+
{
3+
"constant": true,
4+
"inputs": [],
5+
"name": "name",
6+
"outputs": [
7+
{
8+
"name": "",
9+
"type": "string"
10+
}
11+
],
12+
"payable": false,
13+
"stateMutability": "view",
14+
"type": "function"
15+
},
16+
{
17+
"constant": false,
18+
"inputs": [
19+
{
20+
"name": "_spender",
21+
"type": "address"
22+
},
23+
{
24+
"name": "_value",
25+
"type": "uint256"
26+
}
27+
],
28+
"name": "approve",
29+
"outputs": [
30+
{
31+
"name": "",
32+
"type": "bool"
33+
}
34+
],
35+
"payable": false,
36+
"stateMutability": "nonpayable",
37+
"type": "function"
38+
},
39+
{
40+
"constant": true,
41+
"inputs": [],
42+
"name": "totalSupply",
43+
"outputs": [
44+
{
45+
"name": "",
46+
"type": "uint256"
47+
}
48+
],
49+
"payable": false,
50+
"stateMutability": "view",
51+
"type": "function"
52+
},
53+
{
54+
"constant": false,
55+
"inputs": [
56+
{
57+
"name": "_from",
58+
"type": "address"
59+
},
60+
{
61+
"name": "_to",
62+
"type": "address"
63+
},
64+
{
65+
"name": "_value",
66+
"type": "uint256"
67+
}
68+
],
69+
"name": "transferFrom",
70+
"outputs": [
71+
{
72+
"name": "",
73+
"type": "bool"
74+
}
75+
],
76+
"payable": false,
77+
"stateMutability": "nonpayable",
78+
"type": "function"
79+
},
80+
{
81+
"constant": true,
82+
"inputs": [],
83+
"name": "decimals",
84+
"outputs": [
85+
{
86+
"name": "",
87+
"type": "uint8"
88+
}
89+
],
90+
"payable": false,
91+
"stateMutability": "view",
92+
"type": "function"
93+
},
94+
{
95+
"constant": true,
96+
"inputs": [
97+
{
98+
"name": "_owner",
99+
"type": "address"
100+
}
101+
],
102+
"name": "balanceOf",
103+
"outputs": [
104+
{
105+
"name": "balance",
106+
"type": "uint256"
107+
}
108+
],
109+
"payable": false,
110+
"stateMutability": "view",
111+
"type": "function"
112+
},
113+
{
114+
"constant": true,
115+
"inputs": [],
116+
"name": "symbol",
117+
"outputs": [
118+
{
119+
"name": "",
120+
"type": "string"
121+
}
122+
],
123+
"payable": false,
124+
"stateMutability": "view",
125+
"type": "function"
126+
},
127+
{
128+
"constant": false,
129+
"inputs": [
130+
{
131+
"name": "_to",
132+
"type": "address"
133+
},
134+
{
135+
"name": "_value",
136+
"type": "uint256"
137+
}
138+
],
139+
"name": "transfer",
140+
"outputs": [
141+
{
142+
"name": "",
143+
"type": "bool"
144+
}
145+
],
146+
"payable": false,
147+
"stateMutability": "nonpayable",
148+
"type": "function"
149+
},
150+
{
151+
"constant": true,
152+
"inputs": [
153+
{
154+
"name": "_owner",
155+
"type": "address"
156+
},
157+
{
158+
"name": "_spender",
159+
"type": "address"
160+
}
161+
],
162+
"name": "allowance",
163+
"outputs": [
164+
{
165+
"name": "",
166+
"type": "uint256"
167+
}
168+
],
169+
"payable": false,
170+
"stateMutability": "view",
171+
"type": "function"
172+
},
173+
{
174+
"payable": true,
175+
"stateMutability": "payable",
176+
"type": "fallback"
177+
},
178+
{
179+
"anonymous": false,
180+
"inputs": [
181+
{
182+
"indexed": true,
183+
"name": "owner",
184+
"type": "address"
185+
},
186+
{
187+
"indexed": true,
188+
"name": "spender",
189+
"type": "address"
190+
},
191+
{
192+
"indexed": false,
193+
"name": "value",
194+
"type": "uint256"
195+
}
196+
],
197+
"name": "Approval",
198+
"type": "event"
199+
},
200+
{
201+
"anonymous": false,
202+
"inputs": [
203+
{
204+
"indexed": true,
205+
"name": "from",
206+
"type": "address"
207+
},
208+
{
209+
"indexed": true,
210+
"name": "to",
211+
"type": "address"
212+
},
213+
{
214+
"indexed": false,
215+
"name": "value",
216+
"type": "uint256"
217+
}
218+
],
219+
"name": "Transfer",
220+
"type": "event"
221+
}
222+
]
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { useTokenBalance } from './useTokenBalance';
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { ethers } from 'ethers';
2+
import { useContext, useEffect, useState } from 'react';
3+
import { Web3Context } from '../..';
4+
import ERC20ABI from './ERC20ABI.json';
5+
import { BigNumber } from '@ethersproject/bignumber';
6+
7+
interface Props {
8+
tokenAddress: string;
9+
accountAddress: string;
10+
}
11+
12+
export function useTokenBalance({ tokenAddress, accountAddress }: Props) {
13+
const context = useContext(Web3Context);
14+
const provider = context?.provider;
15+
16+
const [balance, setBalance] = useState<BigNumber>();
17+
const [decimals, setDecimals] = useState();
18+
const [loading, setLoading] = useState(true);
19+
const [error, setError] = useState(false);
20+
21+
const getBalance = async () => {
22+
const contract = new ethers.Contract(tokenAddress, ERC20ABI, provider!);
23+
const balance = await contract.balanceOf(accountAddress);
24+
const decimals = await contract.decimals();
25+
setBalance(balance);
26+
setDecimals(decimals);
27+
};
28+
29+
useEffect(() => {
30+
if (tokenAddress && accountAddress && provider) {
31+
setError(false);
32+
setLoading(true);
33+
try {
34+
getBalance();
35+
} catch (error) {
36+
console.error(error);
37+
setError(true);
38+
}
39+
setLoading(false);
40+
}
41+
}, [tokenAddress, accountAddress]);
42+
43+
return {
44+
balance: balance?.toString(), // The balance in wei
45+
loading,
46+
error,
47+
decimals,
48+
formattedBalance: balance && ethers.utils.formatUnits(balance, decimals), // The balance in ethers eg. 0.01 ETH, 20 GTC, etc.
49+
balanceInBigNumber: balance,
50+
};
51+
}

packages/hooks/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export { useWallet } from './hooks';
2+
export { useTokenBalance } from './hooks/useTokenBalance';
23
export { Provider, Web3Context } from './Provider';
34
export type { ProviderProps, Web3ContextType } from './Provider';
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { storiesOf } from '@storybook/react';
2+
import React from 'react';
3+
import { Button } from '@chakra-ui/react';
4+
import { Provider, useTokenBalance, useWallet } from '..';
5+
6+
const GTC_ADDRESS = '0xde30da39c46104798bb5aa3fe8b9e0e1f348163f';
7+
8+
const Default = () => {
9+
const { connection, connectWallet, disconnectWallet, connected } = useWallet();
10+
const { balance, formattedBalance, loading, error } = useTokenBalance({
11+
tokenAddress: GTC_ADDRESS,
12+
accountAddress: connection.userAddress!, // you can test using 0x0ED6Cec17F860fb54E21D154b49DAEFd9Ca04106
13+
});
14+
15+
if (connected) {
16+
return (
17+
<div>
18+
<Button onClick={disconnectWallet}>Disconnect wallet</Button>
19+
<p>{connection.ens || connection.userAddress}</p>
20+
{error ? (
21+
<p>Error occured while trying to fetch balance.</p>
22+
) : loading ? (
23+
<p>Loading...</p>
24+
) : (
25+
<p>
26+
GTC balance: {balance} wei, {formattedBalance} GTC
27+
</p>
28+
)}
29+
</div>
30+
);
31+
}
32+
33+
return <button onClick={connectWallet}>Connect Wallet</button>;
34+
};
35+
36+
storiesOf('UseTokenBalance', module).add('Default', () => (
37+
<Provider network='mainnet'>
38+
<Default />
39+
</Provider>
40+
));

tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,8 @@
1717
"pretty": true,
1818
"sourceMap": true,
1919
"strict": true,
20-
"target": "es5"
20+
"target": "es5",
21+
"resolveJsonModule": true
2122
},
2223
"exclude": ["node_modules"],
2324
"include": ["./packages/*/src"]

0 commit comments

Comments
 (0)