-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathwithdraw.tsx
135 lines (126 loc) · 4.2 KB
/
withdraw.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
import {
useSwapCanisterBalances,
useSwapCanisterController,
useSwapCanisterLists,
} from '@/hooks';
import { selectPlugState, useAppSelector } from '@/store';
import { Assets, toExponential, Token } from '@psychedelic/sonic-js';
import { ChangeEvent, useState } from 'react';
/**
* Withdraw Section React Component
* Example of a component that withdraw tokens from swap canister
*/
export const WithdrawSection = () => {
// Use custom hooks as states from store
const { tokenList } = useSwapCanisterLists();
const { updateBalanceList, balanceList } = useSwapCanisterBalances();
const controller = useSwapCanisterController();
const { principal } = useAppSelector(selectPlugState);
// Create states used for withdraw
const [selectedToken, setSelectedToken] = useState<Token.Data>({
amount: '0',
});
const [isWithdrawRunning, setIsWithdrawRunning] = useState<boolean>(false);
// If there is no principal we can't swap
if (!principal) {
return (
<section>
<h1>Withdraw</h1>
<span>Connect to plug to withdraw</span>
</section>
);
}
// Await fetching tokenList and balanceList
if (!tokenList || !balanceList) {
return (
<section>
<h1>Withdraw</h1>
<span>Loading...</span>
</section>
);
}
// Create a handler for selecting token
const handleTokenSelect = (e: ChangeEvent<HTMLSelectElement>) => {
const tokenId = e.currentTarget.value;
setSelectedToken({ ...selectedToken, metadata: tokenList[tokenId] });
};
// Create a handler for changing token amount
const handleAmountChange = (e: ChangeEvent<HTMLInputElement>) => {
setSelectedToken({ ...selectedToken, amount: e.currentTarget.value });
};
/**
* Create a handler for withdraw tokens using the controller and
* managing app states.
*/
const handleWithdraw = () => {
if (!controller || !selectedToken.metadata) return;
setIsWithdrawRunning(true);
controller
.withdraw({
tokenId: selectedToken.metadata.id,
amount: selectedToken.amount,
})
.then(() => Promise.resolve(updateBalanceList()))
.catch((error) => alert(`Withdraw failed: ${error}`))
.finally(() => setIsWithdrawRunning(false));
};
return (
<section>
<h1>Withdraw</h1>
{isWithdrawRunning ? (
<span>Loading...</span>
) : (
<>
<div>
Token:
<select
name="from"
onChange={handleTokenSelect}
value={selectedToken.metadata?.id || ''}
>
<option value="" style={{ display: 'none' }}></option>
{/** Show all available tokens for withdraw */}
{Object.values(tokenList).map((token) => (
<option value={token.id} key={token.id}>
{token.symbol}
</option>
))}
</select>
{/** Set maximum value using balance */}
{/** Set step using token decimals */}
<input
type="number"
min={0}
max={
selectedToken.metadata &&
balanceList[selectedToken.metadata.id].sonic.toNumber()
}
step={
selectedToken.metadata &&
toExponential(-selectedToken.metadata.decimals).toNumber()
}
value={selectedToken.amount}
onChange={handleAmountChange}
/>
<button onClick={handleWithdraw}>Withdraw</button>
</div>
{selectedToken.metadata && (
<span>
<b>Received {selectedToken.metadata.symbol}: </b>
{/**
* Calculate the received amount after withdraw.
* This applies token fee for transferring.
*/}
{Assets.getWithdrawAmount({
token: selectedToken.metadata,
amount: selectedToken.amount,
}).toString()}
</span>
)}
</>
)}
</section>
);
};