Skip to content

Commit

Permalink
Merge pull request #1862 from zeitgeistpm/tr-setting-changes
Browse files Browse the repository at this point in the history
Setting changes
  • Loading branch information
Robiquet authored Oct 9, 2023
2 parents 9cbe474 + c2c734a commit a0085ca
Show file tree
Hide file tree
Showing 6 changed files with 246 additions and 55 deletions.
91 changes: 91 additions & 0 deletions components/settings/FeePayingAssetSelect.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import AssetSelect, { AssetOption } from "components/ui/AssetSelect";
import {
FOREIGN_ASSET_METADATA,
findAssetImageForSymbol,
} from "lib/constants/foreign-asset";
import { useAllAssetMetadata } from "lib/hooks/queries/useAssetMetadata";
import useFeePayingAssetSelection from "lib/state/fee-paying-asset";
import { useMemo, useState } from "react";
import { Check } from "react-feather";

const isSupportedAsset = (id: number) => {
return Object.keys(FOREIGN_ASSET_METADATA).includes(`${id}`);
};

const defaultSelection = {
label: "Default",
additionalText: "Uses first available asset",
};

const FeePayingAssetSelect = () => {
const { data: assetMetadata, isSuccess } = useAllAssetMetadata();
const { assetSelection, setAsset } = useFeePayingAssetSelection();
const [showSaved, setShowSaved] = useState(false);

const options = useMemo<AssetOption[]>(() => {
if (!isSuccess) {
return [];
}
let options: AssetOption[] = [];
for (const [id, meta] of assetMetadata) {
if (id === "Ztg") {
options = [
...options,
{
label: meta.symbol,
value: { Ztg: null },
image: findAssetImageForSymbol(),
},
];
} else {
if (!isSupportedAsset(id)) {
continue;
}
options = [
...options,
{
label: meta.symbol,
value: { ForeignAsset: id },
image: findAssetImageForSymbol(meta.symbol),
},
];
}
}

options.push(defaultSelection);
return options;
}, [assetMetadata, isSuccess]);

return (
<div className="flex flex-col gap-y-3">
<div className="flex item-center">
<label className="font-bold">Select asset to pay network fees</label>
{showSaved && (
<div className="flex gap-2 items-center ml-auto">
<Check size={16} className="text-green-500" />
<div className="text-sm">Saved</div>
</div>
)}
</div>
<div
className={
"h-14 w-full bg-anti-flash-white rounded-md relative border-1 border-transparent "
}
>
<AssetSelect
options={options}
selectedOption={assetSelection}
showArrowRight={true}
onChange={(option) => {
setAsset(option);
setShowSaved(true);
setTimeout(() => {
setShowSaved(false);
}, 1000);
}}
/>
</div>
</div>
);
};
export default FeePayingAssetSelect;
21 changes: 20 additions & 1 deletion components/settings/OtherSettingsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import { isRpcSdk } from "@zeitgeistpm/sdk-next";
import { useSdkv2 } from "lib/hooks/useSdkv2";
import { useWallet } from "lib/state/wallet";
import { isValidPolkadotAddress } from "lib/util";
import InfoPopover from "components/ui/InfoPopover";
import { AiOutlineInfoCircle } from "react-icons/ai";

export type OtherSettingsFormProps = {};

Expand Down Expand Up @@ -57,7 +59,24 @@ const OtherSettingsForm: React.FC<OtherSettingsFormProps> = ({}) => {
reset(data);
})}
>
<label className="font-bold mb-2">Proxy Account</label>
<div className="flex items-center mb-2 gap-3">
<label className="font-bold ">Proxy Account</label>
<InfoPopover
title={
<h3 className="flex justify-center items-center mb-4 gap-2">
<AiOutlineInfoCircle />
Proxy Accounts
</h3>
}
>
<p>
Proxy accounts can be used to allow wallets to sign transactions on
behalf of others. This section allows you to tell this application
to attempt to sign transactions using the connected wallet on behalf
of another account.
</p>
</InfoPopover>
</div>
<div className="flex flex-row p-2 mb-2">
<input
type="checkbox"
Expand Down
30 changes: 23 additions & 7 deletions components/settings/SettingsModal.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React, { Fragment, useState } from "react";
import { Dialog, Tab } from "@headlessui/react";
import Modal from "components/ui/Modal";
import AcccountSettingsForm from "./AccountSettingsForm";
import OtherSettingsForm from "./OtherSettingsForm";
import { useIdentity } from "lib/hooks/queries/useIdentity";
import { useWallet } from "lib/state/wallet";
import { AddressOption } from "components/ui/AddressInput";
import React, { Fragment } from "react";
import AcccountSettingsForm from "./AccountSettingsForm";
import FeePayingAssetSelect from "./FeePayingAssetSelect";
import OtherSettingsForm from "./OtherSettingsForm";

export type SettingsModalProps = {
open: boolean;
Expand All @@ -14,7 +14,8 @@ export type SettingsModalProps = {

enum TabSelection {
Account,
Other,
Proxy,
Fees,
}

const SettingsModal: React.FC<SettingsModalProps> = ({ open, onClose }) => {
Expand Down Expand Up @@ -58,7 +59,21 @@ const SettingsModal: React.FC<SettingsModalProps> = ({ open, onClose }) => {
(selected ? "font-semibold text-black" : "")
}
>
Other Settings
Proxy
</span>
)}
</Tab>
</div>
<div className="flex-grow center">
<Tab as={Fragment}>
{({ selected }) => (
<span
className={
"cursor-pointer text-sm " +
(selected ? "font-semibold text-black" : "")
}
>
Fee Paying Asset
</span>
)}
</Tab>
Expand All @@ -73,7 +88,8 @@ const SettingsModal: React.FC<SettingsModalProps> = ({ open, onClose }) => {
) : (
<></>
),
[TabSelection.Other]: <OtherSettingsForm />,
[TabSelection.Proxy]: <OtherSettingsForm />,
[TabSelection.Fees]: <FeePayingAssetSelect />,
}[tabSelection]
}
</Dialog.Panel>
Expand Down
54 changes: 34 additions & 20 deletions components/ui/AssetSelect.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,9 @@ import Select, {

export type AssetOption = {
label: string;
value: AssetId;
image: string;
value?: AssetId;
image?: string;
additionalText?: string;
};

const Control = ({ children, ...rest }: ControlProps<AssetOption, false>) => {
Expand Down Expand Up @@ -52,21 +53,25 @@ const SingleValue = (props: SingleValueProps<AssetOption, false>) => {
const { label, image } = props.data;
return (
<div className="flex items-center font-semibold">
<Image
src={image}
width={36}
height={36}
className="mr-3"
alt={label}
quality={100}
/>
{image ? (
<Image
src={image}
width={36}
height={36}
className="mr-3"
alt={label}
quality={100}
/>
) : (
<div className="w-[36px] h-[36px] rounded-full bg-ztg-blue mr-3"></div>
)}
<span>{label}</span>
</div>
);
};

const Option = (props: OptionProps<AssetOption, false>) => {
const { label, value, image } = props.data;
const { label, value, image, additionalText } = props.data;
const wallet = useWallet();
const address = wallet.activeAccount?.address;

Expand All @@ -77,20 +82,27 @@ const Option = (props: OptionProps<AssetOption, false>) => {
{...props}
className="!flex items-center w-full bg-anti-flash-white rounded-md h-14 mb-2 last:mb-0 font-semibold px-4 !cursor-pointer"
>
<Image
src={image}
width={36}
height={36}
className="mr-3"
alt={label}
quality={100}
/>
{image ? (
<Image
src={image}
width={36}
height={36}
className="mr-3"
alt={label}
quality={100}
/>
) : (
<div className="w-[36px] h-[36px] rounded-full bg-ztg-blue mr-3"></div>
)}
<span>{label}</span>
{balance && (
<div className="ml-auto text-xs">
Balance: {formatNumberLocalized(balance.div(ZTG).toNumber())}
</div>
)}
{additionalText && (
<div className="ml-auto text-xs">{additionalText}</div>
)}
</components.Option>
);
};
Expand All @@ -110,16 +122,18 @@ export type AssetSelectProps = {
options: AssetOption[];
selectedOption?: AssetOption;
onChange: (value: AssetOption) => void;
showArrowRight?: boolean;
};

const AssetSelect: React.FC<AssetSelectProps> = ({
options,
selectedOption,
onChange,
showArrowRight = false,
}) => {
return (
<Select
className="w-34 h-full !static"
className={`h-full !static ${showArrowRight ? "pr-4" : "w-34"}`}
isSearchable={false}
options={options}
unstyled={true}
Expand Down
80 changes: 53 additions & 27 deletions lib/hooks/queries/useFeePayingAsset.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { UseQueryResult, useQuery } from "@tanstack/react-query";
import { AssetId, ZTG } from "@zeitgeistpm/sdk-next";
import { AssetId, IOZtgAssetId, ZTG } from "@zeitgeistpm/sdk-next";
import Decimal from "decimal.js";
import { useWallet } from "lib/state/wallet";
import { useAssetMetadata } from "./useAssetMetadata";
import { useBalance } from "./useBalance";
import { useChainConstants } from "./useChainConstants";
import { useZtgBalance } from "./useZtgBalance";
import useFeePayingAssetSelection from "lib/state/fee-paying-asset";

type FeeAsset = {
assetId: AssetId;
Expand All @@ -30,6 +31,7 @@ export const useFeePayingAsset = (
const { data: dotBalance } = useBalance(activeAccount?.address, {
ForeignAsset: 0,
});
const { assetSelection } = useFeePayingAssetSelection();

const enabled =
!!nativeBalance &&
Expand All @@ -46,38 +48,62 @@ export const useFeePayingAsset = (
nativeBalance,
dotBalance,
baseFee,
assetSelection,
],
async () => {
if (enabled) {
// if user has ztg, use that to pay
if (nativeBalance.greaterThanOrEqualTo(baseFee)) {
return {
assetId: { Ztg: null },
symbol: constants?.tokenSymbol ?? "",
amount: baseFee,
sufficientBalance: true,
};
}
if (assetSelection.label === "Default") {
// if user has ztg, use that to pay
if (nativeBalance.greaterThanOrEqualTo(baseFee)) {
return {
assetId: { Ztg: null },
symbol: constants?.tokenSymbol ?? "",
amount: baseFee,
sufficientBalance: true,
};
}

const dotFeeFactor = dotMetadata.feeFactor.div(ZTG);
const dotFee = baseFee.mul(dotFeeFactor).mul(foreignAssetFeeBuffer);
const dotFeeFactor = dotMetadata.feeFactor.div(ZTG);
const dotFee = baseFee.mul(dotFeeFactor).mul(foreignAssetFeeBuffer);

if (dotBalance.greaterThan(dotFee)) {
return {
assetId: {
ForeignAsset: 0,
},
symbol: dotMetadata.symbol,
amount: dotFee,
sufficientBalance: true,
};
if (dotBalance.greaterThan(dotFee)) {
return {
assetId: {
ForeignAsset: 0,
},
symbol: dotMetadata.symbol,
amount: dotFee,
sufficientBalance: true,
};
} else {
return {
assetId: { Ztg: null },
symbol: constants?.tokenSymbol ?? "",
amount: baseFee,
sufficientBalance: false,
};
}
} else {
return {
assetId: { Ztg: null },
symbol: constants?.tokenSymbol ?? "",
amount: baseFee,
sufficientBalance: false,
};
const isNative = IOZtgAssetId.is(assetSelection.value);
if (isNative) {
return {
assetId: { Ztg: null },
symbol: constants?.tokenSymbol ?? "",
amount: baseFee,
sufficientBalance: true,
};
} else {
const dotFeeFactor = dotMetadata.feeFactor.div(ZTG);
const dotFee = baseFee.mul(dotFeeFactor).mul(foreignAssetFeeBuffer);
return {
assetId: {
ForeignAsset: 0,
},
symbol: dotMetadata.symbol,
amount: dotFee,
sufficientBalance: dotBalance.greaterThan(dotFee),
};
}
}
}
return null;
Expand Down
Loading

0 comments on commit a0085ca

Please sign in to comment.