From 284e510761a5f0e46638adbdf521b61a1d109a5c Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Fri, 14 Apr 2023 17:26:20 +0200 Subject: [PATCH 01/15] Query gasprice --- components/chainSelect/ChainSelect.tsx | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/components/chainSelect/ChainSelect.tsx b/components/chainSelect/ChainSelect.tsx index 127a9b3..31d9a2e 100644 --- a/components/chainSelect/ChainSelect.tsx +++ b/components/chainSelect/ChainSelect.tsx @@ -135,7 +135,16 @@ const ChainSelect = () => { const firstAsset: ChainRegistryAsset | undefined = assetData.assets?.[0]; const denom = firstAsset?.base || ""; const displayDenom = firstAsset?.symbol || ""; - const gasPrice = firstAsset ? `0.03${firstAsset.base}` : ""; + const feeToken = chainData["fees"]?.fee_tokens.find( + (token: { denom: string }) => token.denom == denom, + ); + const gasPrice = + feeToken["average_gas_price"] ?? + feeToken["low_gas_price"] ?? + feeToken["high_gas_price"] ?? + feeToken["fixed_min_gas_price"] ?? + 0.03; + const formattedGasPrice = firstAsset ? `${gasPrice}${denom}` : ""; const displayUnit = firstAsset?.denom_units.find((u) => u.denom == firstAsset.display); const displayDenomExponent = displayUnit?.exponent ?? 6; @@ -151,7 +160,7 @@ const ChainSelect = () => { denom, displayDenom, displayDenomExponent, - gasPrice, + gasPrice: formattedGasPrice, chainId, chainDisplayName, registryName, From b6338db0a1a526572f7aef39bbe0d0c39de7a85b Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Fri, 14 Apr 2023 17:28:32 +0200 Subject: [PATCH 02/15] Check good rpc from array --- components/chainSelect/ChainSelect.tsx | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/components/chainSelect/ChainSelect.tsx b/components/chainSelect/ChainSelect.tsx index 127a9b3..7eaf0d9 100644 --- a/components/chainSelect/ChainSelect.tsx +++ b/components/chainSelect/ChainSelect.tsx @@ -125,7 +125,7 @@ const ChainSelect = () => { const { data: chainData } = await axios.get(chainInfoUrl); const { data: assetData } = await axios.get(chainAssetUrl); - const nodeAddress = getNodeFromArray(chainData.apis.rpc); + const nodeAddress = await getNodeFromArray(chainData.apis.rpc); const addressPrefix = chainData["bech32_prefix"]; const chainId = chainData["chain_id"]; const chainDisplayName = chainData["pretty_name"]; @@ -139,10 +139,6 @@ const ChainSelect = () => { const displayUnit = firstAsset?.denom_units.find((u) => u.denom == firstAsset.display); const displayDenomExponent = displayUnit?.exponent ?? 6; - // test client connection - const client = await StargateClient.connect(nodeAddress); - await client.getHeight(); - // change app state dispatch({ type: "changeChain", @@ -175,13 +171,26 @@ const ChainSelect = () => { return ""; }; - const getNodeFromArray = (nodeArray: { address: string; provider: string }[]) => { + const getNodeFromArray = async (nodeArray: { address: string; provider: string }[]) => { // only return https connections - const secureNodes = nodeArray.filter((node) => node.address.includes("https://")); + const secureNodes = nodeArray + .filter((node) => node.address.includes("https://")) + .map(({ address }) => address); + if (secureNodes.length === 0) { throw new Error("No SSL enabled RPC nodes available for this chain"); } - return secureNodes[0].address; + + try { + for (const node of secureNodes) { + // test client connection + const client = await StargateClient.connect(node); + await client.getHeight(); + return node; + } + } catch {} + + throw new Error("No RPC nodes available for this chain"); }; const onChainSelect = (option: ChainOption) => { From 4ee7903b05e0f6c447ca29e3531af76b5dbdcb15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Abel=20Fern=C3=A1ndez?= <44572727+abefernan@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:37:26 +0200 Subject: [PATCH 03/15] Improve secure url checking Co-authored-by: Simon Warta <2603011+webmaster128@users.noreply.github.com> --- components/chainSelect/ChainSelect.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/chainSelect/ChainSelect.tsx b/components/chainSelect/ChainSelect.tsx index 7eaf0d9..b9aaca4 100644 --- a/components/chainSelect/ChainSelect.tsx +++ b/components/chainSelect/ChainSelect.tsx @@ -174,7 +174,7 @@ const ChainSelect = () => { const getNodeFromArray = async (nodeArray: { address: string; provider: string }[]) => { // only return https connections const secureNodes = nodeArray - .filter((node) => node.address.includes("https://")) + .filter((node) => node.address.startsWith("https://")) .map(({ address }) => address); if (secureNodes.length === 0) { From 962a239a9b54248c2f286cdba15d3950f1a6b2b3 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:40:15 +0200 Subject: [PATCH 04/15] Fix try catch in for loop --- components/chainSelect/ChainSelect.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/components/chainSelect/ChainSelect.tsx b/components/chainSelect/ChainSelect.tsx index b9aaca4..3f1150b 100644 --- a/components/chainSelect/ChainSelect.tsx +++ b/components/chainSelect/ChainSelect.tsx @@ -181,14 +181,14 @@ const ChainSelect = () => { throw new Error("No SSL enabled RPC nodes available for this chain"); } - try { - for (const node of secureNodes) { + for (const node of secureNodes) { + try { // test client connection const client = await StargateClient.connect(node); await client.getHeight(); return node; - } - } catch {} + } catch {} + } throw new Error("No RPC nodes available for this chain"); }; From ddc374d4e74adaf2820a09b094311c550a00ce74 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:43:18 +0200 Subject: [PATCH 05/15] Add empty object fallback for feeToken --- components/chainSelect/ChainSelect.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/components/chainSelect/ChainSelect.tsx b/components/chainSelect/ChainSelect.tsx index 31d9a2e..1945db7 100644 --- a/components/chainSelect/ChainSelect.tsx +++ b/components/chainSelect/ChainSelect.tsx @@ -135,9 +135,9 @@ const ChainSelect = () => { const firstAsset: ChainRegistryAsset | undefined = assetData.assets?.[0]; const denom = firstAsset?.base || ""; const displayDenom = firstAsset?.symbol || ""; - const feeToken = chainData["fees"]?.fee_tokens.find( - (token: { denom: string }) => token.denom == denom, - ); + const feeToken = + chainData["fees"]?.fee_tokens.find((token: { denom: string }) => token.denom == denom) ?? + {}; const gasPrice = feeToken["average_gas_price"] ?? feeToken["low_gas_price"] ?? From 6aa535b7bbdcea4e6ac9b4932d1ea70cbb5142e8 Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:48:54 +0200 Subject: [PATCH 06/15] Add spinner component --- components/Spinner.tsx | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 components/Spinner.tsx diff --git a/components/Spinner.tsx b/components/Spinner.tsx new file mode 100644 index 0000000..18f7586 --- /dev/null +++ b/components/Spinner.tsx @@ -0,0 +1,30 @@ +interface SpinnerProps { + readonly size?: number; +} + +const Spinner = ({ size }: SpinnerProps) => ( + <> +
+ + +); + +export default Spinner; From a6082905c7e3da83bcb0a1c83e028d4ac0c2283a Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:49:09 +0200 Subject: [PATCH 07/15] Add loading feature to Button --- components/inputs/Button.tsx | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/components/inputs/Button.tsx b/components/inputs/Button.tsx index 860fa3f..0bf2e7d 100644 --- a/components/inputs/Button.tsx +++ b/components/inputs/Button.tsx @@ -1,7 +1,8 @@ -import React from "react"; +import Spinner from "../Spinner"; interface Props { primary?: boolean; + loading?: boolean; disabled?: boolean; href?: string; label: string; @@ -17,10 +18,18 @@ const Button = (props: Props) => ( ) : ( )} ); From f0ff98cd7e8927dde7f893f7b5aa4dde88081abb Mon Sep 17 00:00:00 2001 From: abefernan <44572727+abefernan@users.noreply.github.com> Date: Mon, 17 Apr 2023 16:50:14 +0200 Subject: [PATCH 08/15] Add loading state to form buttons --- components/forms/DelegationForm.tsx | 6 +++--- components/forms/MultisigForm.tsx | 19 +++++++++---------- components/forms/ReDelegationForm.tsx | 4 ++-- components/forms/RewardsForm.tsx | 4 ++-- components/forms/TransactionForm.tsx | 15 +++++++-------- components/forms/UnDelegationForm.tsx | 4 ++-- 6 files changed, 25 insertions(+), 27 deletions(-) diff --git a/components/forms/DelegationForm.tsx b/components/forms/DelegationForm.tsx index e8cfddd..8cb44ab 100644 --- a/components/forms/DelegationForm.tsx +++ b/components/forms/DelegationForm.tsx @@ -3,7 +3,7 @@ import { Account, calculateFee } from "@cosmjs/stargate"; import { assert } from "@cosmjs/utils"; import axios from "axios"; import { NextRouter, withRouter } from "next/router"; -import React, { useState } from "react"; +import { useState } from "react"; import { useAppContext } from "../../context/AppContext"; import { checkAddress, exampleValidatorAddress } from "../../lib/displayHelpers"; import Button from "../inputs/Button"; @@ -24,7 +24,7 @@ const DelegationForm = (props: Props) => { const [memo, setMemo] = useState(""); const [gas, setGas] = useState(200000); const [gasPrice, _setGasPrice] = useState(state.chain.gasPrice); - const [_processing, setProcessing] = useState(false); + const [processing, setProcessing] = useState(false); const [addressError, setAddressError] = useState(""); const createTransaction = (txValidatorAddress: string, txAmount: string, gasLimit: number) => { @@ -130,7 +130,7 @@ const DelegationForm = (props: Props) => { onChange={(e: React.ChangeEvent) => setMemo(e.target.value)} /> -