Skip to content

Commit 3160a10

Browse files
committed
chore: dynamic fees calculations
1 parent 26f0a9b commit 3160a10

File tree

8 files changed

+213
-36
lines changed

8 files changed

+213
-36
lines changed

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,10 @@
3737
"@types/react-redux": "^7.1.9",
3838
"@types/react-router-dom": "^5.1.5",
3939
"@walletconnect/web3-provider": "^1.3.1",
40+
"bignumber.js": "^9.0.2",
4041
"classnames": "^2.2.6",
4142
"dotenv": "^10.0.0",
43+
"ethers": "^5.5.2",
4244
"i18next": "^20.3.3",
4345
"i18next-browser-languagedetector": "^6.1.2",
4446
"i18next-http-backend": "^1.2.6",

src/components/progress/ProgressHelpers.tsx

+14-7
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
} from "@material-ui/core";
99
import { makeStyles } from "@material-ui/core/styles";
1010
import DoneIcon from "@material-ui/icons/Done";
11+
import { Skeleton } from "@material-ui/lab";
1112
import classNames from "classnames";
1213
import React, { FunctionComponent, ReactNode } from "react";
1314
import {
@@ -147,7 +148,9 @@ export const ProgressWrapper = styled("div")({
147148
marginBottom: 20,
148149
});
149150

150-
export const ProgressWithContent: FunctionComponent<ProgressWithContentProps> = ({
151+
export const ProgressWithContent: FunctionComponent<
152+
ProgressWithContentProps
153+
> = ({
151154
color,
152155
value = 100,
153156
processing,
@@ -243,11 +246,9 @@ type TransactionStatusInfoProps = {
243246
status?: string;
244247
};
245248

246-
export const TransactionStatusInfo: FunctionComponent<TransactionStatusInfoProps> = ({
247-
status = "Pending",
248-
chain,
249-
address,
250-
}) => {
249+
export const TransactionStatusInfo: FunctionComponent<
250+
TransactionStatusInfoProps
251+
> = ({ status = "Pending", chain, address }) => {
251252
const styles = useTransactionStatusInfoStyles();
252253
return (
253254
<div className={styles.root}>
@@ -353,7 +354,9 @@ export type TransactionStatusIndicatorProps = {
353354
targetConfirmations?: number;
354355
};
355356

356-
export const TransactionStatusIndicator: FunctionComponent<TransactionStatusIndicatorProps> = ({
357+
export const TransactionStatusIndicator: FunctionComponent<
358+
TransactionStatusIndicatorProps
359+
> = ({
357360
needsAction,
358361
showConfirmations = true,
359362
confirmations,
@@ -382,3 +385,7 @@ export const TransactionStatusIndicator: FunctionComponent<TransactionStatusIndi
382385
</div>
383386
);
384387
};
388+
389+
export const InlineSkeleton = styled(Skeleton)({
390+
display: "inline-block",
391+
});

src/components/utils/Debug.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ const useStyles = makeStyles({
2929
},
3030
});
3131

32-
const off = true; // process.env.NODE_ENV === "production";
32+
const off = false; // process.env.NODE_ENV === "production";
3333

3434
type DebugProps = {
3535
it: any;

src/features/gateway/gatewayHooks.ts

+117-16
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,36 @@
11
import { Asset, Chain } from "@renproject/chains";
2+
import { Ethereum } from "@renproject/chains-ethereum";
23
import RenJS, { Gateway, GatewayTransaction } from "@renproject/ren";
34
import { RenNetwork } from "@renproject/utils";
5+
import BigNumber from "bignumber.js";
6+
import { ethers } from "ethers";
47
import { useCallback, useEffect, useState } from "react";
5-
import { ChainInstanceMap } from "../chain/chainUtils";
8+
import { alterEthereumBaseChainSigner } from "../chain/chainUtils";
9+
import { useChains } from "../network/networkHooks";
10+
import { useWallet } from "../wallet/walletHooks";
611
import { createGateway } from "./gatewayUtils";
712

813
type UseGatewayParams = {
914
network: RenNetwork;
1015
asset: Asset;
11-
fromChain: Chain;
12-
toChain: Chain;
16+
from: Chain;
17+
to: Chain;
1318
amount?: string;
1419
nonce?: number;
1520
};
1621

17-
export const useGateway = (
18-
{ asset, fromChain, toChain, amount, network, nonce }: UseGatewayParams,
19-
renJs: RenJS | null,
20-
chains: ChainInstanceMap
21-
) => {
22+
export const useGateway = ({
23+
asset,
24+
from,
25+
to,
26+
amount,
27+
network,
28+
nonce,
29+
}: UseGatewayParams) => {
30+
const chains = useChains(network);
31+
const { provider } = useWallet(to);
32+
const [renJs, setRenJs] = useState<RenJS | null>(null);
33+
const [error, setError] = useState(null);
2234
const [gateway, setGateway] = useState<Gateway | null>(null);
2335
const [transactions, setTransactions] = useState<Array<GatewayTransaction>>(
2436
[]
@@ -28,33 +40,122 @@ export const useGateway = (
2840
setTransactions((txs) => [...txs, tx]);
2941
}, []);
3042

43+
// set up renjs with signers
3144
useEffect(() => {
32-
console.log("useGateway useEffect");
45+
console.log("useGateway useEffect renJs and provider");
46+
const initProvider = async () => {
47+
const ethersProvider = new ethers.providers.Web3Provider(provider);
48+
const signer = ethersProvider.getSigner();
49+
console.log("useGateway altering signer");
50+
alterEthereumBaseChainSigner(chains, signer);
51+
const renJs = new RenJS(network).withChains(
52+
// @ts-ignore
53+
...Object.values(chains).map((chain) => chain.chain)
54+
);
55+
(window as any).renJs = renJs;
56+
return renJs;
57+
};
58+
initProvider()
59+
.then((renJs) => setRenJs(renJs))
60+
.catch((error) => {
61+
setError(error);
62+
});
63+
}, [network]);
64+
65+
// initialize gateway
66+
useEffect(() => {
67+
console.log("useGateway useEffect gateway init");
3368
if (renJs) {
34-
console.log("initializeGateway");
3569
const initializeGateway = async () => {
3670
const gateway = await createGateway(
3771
renJs,
38-
{ asset, from: fromChain, to: toChain, amount, nonce },
72+
{ asset, from, to, amount, nonce },
3973
chains
4074
);
4175
console.log("gateway created", gateway);
4276
gateway.on("transaction", addTransaction);
43-
console.log("gateway transaction listener registered", addTransaction);
44-
(window as any).g = gateway;
77+
console.log("gateway transaction listener added");
78+
(window as any).gateway = gateway;
4579
return gateway;
4680
};
81+
console.log("gateway initializing");
4782
initializeGateway()
4883
.then((gateway) => setGateway(gateway))
49-
.catch(console.error);
84+
.catch((error) => {
85+
setError(error);
86+
});
5087
}
5188

5289
return () => {
5390
if (gateway) {
91+
console.log("gateway removing listeners");
5492
gateway.eventEmitter.removeAllListeners();
5593
}
5694
};
57-
}, [renJs]); // of useEffect
95+
}, [renJs]);
96+
97+
return { renJs, gateway, transactions, error };
98+
};
99+
100+
export const useGatewayFees = (
101+
gateway: Gateway | null,
102+
amount: string | number | BigNumber
103+
) => {
104+
const [decimals, setDecimals] = useState(0);
105+
const [balance, setBalance] = useState("");
106+
const [balancePending, setBalancePending] = useState(false);
107+
const [minimumAmount, setMinimumAmount] = useState("");
108+
const [outputAmount, setOutputAmount] = useState("");
109+
const [amountsPending, setAmountsPending] = useState(false);
110+
111+
useEffect(() => {
112+
setBalancePending(true);
113+
if (!gateway) {
114+
return;
115+
}
116+
const getFees = async () => {
117+
const decimals = await gateway.fromChain.assetDecimals(
118+
gateway.params.asset
119+
);
120+
setDecimals(decimals);
121+
console.log(
122+
`gateway decimals ${gateway.fromChain.chain}/${gateway.params.asset}: ${decimals}`
123+
);
124+
125+
const balanceBn = (
126+
await (gateway.toChain as Ethereum).getBalance(gateway.params.asset)
127+
).shiftedBy(-decimals);
128+
setBalance(balanceBn.toFixed());
129+
console.log(`gateway balance: ${balanceBn}`);
130+
setBalancePending(false);
131+
};
132+
getFees().catch(console.error);
133+
}, [gateway]);
134+
135+
useEffect(() => {
136+
setAmountsPending(true);
137+
if (!gateway || !decimals) {
138+
return;
139+
}
140+
const estimatedOutputBn = gateway.fees
141+
// @ts-ignore
142+
.estimateOutput(new BigNumber(amount).shiftedBy(decimals))
143+
.shiftedBy(-decimals);
144+
setOutputAmount(estimatedOutputBn.toFixed());
145+
console.log(`gateway estimated output: ${estimatedOutputBn}`);
146+
147+
const minimumAmountBn = gateway.fees.minimumAmount.shiftedBy(-decimals);
148+
setMinimumAmount(minimumAmountBn.toFixed());
149+
console.log(`gateway minimum amount: ${estimatedOutputBn}`);
150+
setAmountsPending(false);
151+
}, [gateway, amount]);
58152

59-
return { gateway, transactions };
153+
return {
154+
decimals,
155+
balance,
156+
balancePending,
157+
minimumAmount,
158+
outputAmount,
159+
amountsPending,
160+
};
60161
};

src/features/gateway/steps/GatwayFeesStep.tsx

+71-10
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
1-
import { Divider, IconButton } from "@material-ui/core";
2-
import { Asset } from "@renproject/chains";
3-
import React, { FunctionComponent, useCallback, useState } from "react";
1+
import { Divider, Fade, IconButton } from "@material-ui/core";
2+
import { Skeleton } from "@material-ui/lab";
3+
import { Ethereum } from "@renproject/chains-ethereum";
4+
import BigNumber from "bignumber.js";
5+
import React, {
6+
FunctionComponent,
7+
useCallback,
8+
useEffect,
9+
useState,
10+
} from "react";
411
import { useTranslation } from "react-i18next";
512
import { useSelector } from "react-redux";
613
import { NumberFormatText } from "../../../components/formatting/NumberFormatText";
@@ -17,15 +24,21 @@ import {
1724
PaperNav,
1825
PaperTitle,
1926
} from "../../../components/layout/Paper";
27+
import { InlineSkeleton } from "../../../components/progress/ProgressHelpers";
2028
import {
2129
AssetInfo,
2230
LabelWithValue,
2331
} from "../../../components/typography/TypographyHelpers";
32+
import { Debug } from "../../../components/utils/Debug";
2433
import {
2534
assetsConfig,
2635
getAssetConfig,
2736
getRenAssetName,
2837
} from "../../../utils/tokensConfig";
38+
import { useChains } from "../../network/networkHooks";
39+
import { $network } from "../../network/networkSlice";
40+
import { useWallet } from "../../wallet/walletHooks";
41+
import { useGateway, useGatewayFees } from "../gatewayHooks";
2942
import { $gateway } from "../gatewaySlice";
3043
import { GatewayStepProps } from "./stepUtils";
3144

@@ -34,6 +47,7 @@ export const GatewayFeesStep: FunctionComponent<GatewayStepProps> = ({
3447
onPrev,
3548
}) => {
3649
const { t } = useTranslation();
50+
const { network } = useSelector($network);
3751
const { asset, from, to } = useSelector($gateway);
3852
const { Icon, shortName } = getAssetConfig(asset);
3953
const renAsset = getRenAssetName(asset);
@@ -46,10 +60,26 @@ export const GatewayFeesStep: FunctionComponent<GatewayStepProps> = ({
4660
}
4761
}, []);
4862

49-
const balance = 42.1;
50-
const showBalance = true;
51-
const receivingFormatted = "42.0";
52-
const receivingFormattedUsd = "69.0";
63+
const { connected } = useWallet(to);
64+
65+
const { gateway, transactions } = useGateway({
66+
asset,
67+
from,
68+
to,
69+
amount,
70+
network,
71+
nonce: 1,
72+
});
73+
74+
const fees = useGatewayFees(gateway, amount);
75+
const {
76+
balance,
77+
balancePending,
78+
outputAmount,
79+
minimumAmount,
80+
amountsPending,
81+
} = fees;
82+
const outputAmountUsd = Number(outputAmount) * 69.42; // TODO
5383

5484
const Header = (
5585
<PaperHeader>
@@ -62,14 +92,43 @@ export const GatewayFeesStep: FunctionComponent<GatewayStepProps> = ({
6292
<PaperActions />
6393
</PaperHeader>
6494
);
95+
if (!connected) {
96+
return (
97+
<>
98+
{Header}
99+
<PaperContent bottomPadding>
100+
<span>Please connect a wallet to proceed</span>
101+
</PaperContent>
102+
</>
103+
);
104+
}
105+
106+
const showBalance = true;
107+
65108
return (
66109
<>
67110
{Header}
68111
<PaperContent bottomPadding>
69112
{showBalance && (
70113
<LabelWithValue
71114
label={t("common.balance-label")}
72-
value={`${balance} ${asset}`}
115+
value={
116+
<span>
117+
{balancePending ? (
118+
<InlineSkeleton
119+
variant="rect"
120+
animation="pulse"
121+
width={40}
122+
height={12}
123+
/>
124+
) : (
125+
<Fade in={true}>
126+
<span>{balance}</span>
127+
</Fade>
128+
)}
129+
<span> {renAsset}</span>
130+
</span>
131+
}
73132
/>
74133
)}
75134
<OutlinedTextField
@@ -83,14 +142,15 @@ export const GatewayFeesStep: FunctionComponent<GatewayStepProps> = ({
83142
label={t("common.receiving-label")}
84143
value={
85144
<NumberFormatText
86-
value={receivingFormatted}
145+
value={outputAmount}
87146
spacedSuffix={renAsset}
147+
decimalScale={3} // TODO: make dynamic decimal scale based on input decimals
88148
/>
89149
}
90150
valueEquivalent={
91151
<NumberFormatText
92152
prefix=" = $"
93-
value={receivingFormattedUsd}
153+
value={outputAmountUsd}
94154
spacedSuffix="USD"
95155
decimalScale={2}
96156
fixedDecimalScale
@@ -104,6 +164,7 @@ export const GatewayFeesStep: FunctionComponent<GatewayStepProps> = ({
104164
<PaperContent topPadding bottomPadding>
105165
<span>Feessss</span>
106166
</PaperContent>
167+
<Debug it={{ fees }} />
107168
</>
108169
);
109170
};

0 commit comments

Comments
 (0)