diff --git a/app/governance/components/ProposalTable/ProposalRow.tsx b/app/governance/components/ProposalTable/ProposalRow.tsx index 00a5d0d7..fded4132 100644 --- a/app/governance/components/ProposalTable/ProposalRow.tsx +++ b/app/governance/components/ProposalTable/ProposalRow.tsx @@ -14,8 +14,13 @@ import Icon from "@/components/icon/icon"; interface ProposalRowProps { proposal: Proposal; active: boolean; + isMobile?: boolean; } -export const ProposalRow = ({ proposal, active }: ProposalRowProps) => { +export const ProposalRow = ({ + proposal, + active, + isMobile, +}: ProposalRowProps) => { const votes = active ? { yes: Number( @@ -46,28 +51,39 @@ export const ProposalRow = ({ proposal, active }: ProposalRowProps) => { direction="column" width="100%" key={`name_${proposal.proposal_id}`} - style={{ cursor: "pointer", alignItems: "left" }} + style={{ + cursor: "pointer", + alignItems: "left", + padding: isMobile ? "16px" : "", + justifyContent: isMobile ? "space-between" : "unset", + }} + height={isMobile ? "100%" : ""} > - + {proposal.proposal_id} @@ -77,110 +93,195 @@ export const ProposalRow = ({ proposal, active }: ProposalRowProps) => { alignItems: "center", marginLeft: "15px", justifyContent: "center", + height: "14px", }} > - + {formatProposalType(proposal.type_url)}
- + {proposal.title}
- , - - + {isMobile && ( - - {active ? "Vote Status" : "Status"} - - - {active ? ( - - - {votes && ( - - )} + {" "} + + + + {active ? "Vote Status" : "Status"} + + {active ? ( + + + {votes && ( + + )} + + + ) : ( + +
+
+
+ + {formatProposalStatus(proposal.status)} + + + )} - ) : ( - -
-
+ -
- - {formatProposalStatus(proposal.status)} - - - )} - + > + + + Time left to Vote + + + + + + + + + + + ) : ( + + + + Voting Date + + + + + + {new Date(proposal.voting_end_time).toDateString()} + + + + )} + + )} , - active ? ( + !isMobile && ( @@ -193,75 +294,148 @@ export const ProposalRow = ({ proposal, active }: ProposalRowProps) => { }} > - Time left to Vote + {active ? "Vote Status" : "Status"} + {active ? ( + + + {votes && ( + + )} + + + ) : ( + +
+
+
+ + {formatProposalStatus(proposal.status)} + + + )} + + + ), + active + ? !isMobile && ( + + + + + Time left to Vote + + + + + + + + + + ) + : !isMobile && ( - - - + + + Voting Date + + + + + + {new Date(proposal.voting_end_time).toDateString()} + + - - - ) : ( + ), + !isMobile && ( - - - Voting Date - - - - - - {new Date(proposal.voting_end_time).toDateString()} - - +
+ +
), - -
- -
-
, ]; }; diff --git a/app/governance/components/ProposalTable/ProposalTable.module.scss b/app/governance/components/ProposalTable/ProposalTable.module.scss index 32f40734..df73b4df 100644 --- a/app/governance/components/ProposalTable/ProposalTable.module.scss +++ b/app/governance/components/ProposalTable/ProposalTable.module.scss @@ -23,7 +23,6 @@ .tableTitleColumn { display: flex; flex-direction: row; - padding-left: 20px; padding-right: 10px; } .proposalStatus { diff --git a/app/governance/components/ProposalTable/ProposalTable.tsx b/app/governance/components/ProposalTable/ProposalTable.tsx index 32cb737c..3b71c14c 100644 --- a/app/governance/components/ProposalTable/ProposalTable.tsx +++ b/app/governance/components/ProposalTable/ProposalTable.tsx @@ -10,9 +10,12 @@ import Container from "@/components/container/container"; import { Pagination } from "@/components/pagination/Pagination"; import Spacer from "@/components/layout/spacer"; import { ProposalRow } from "./ProposalRow"; +import Analytics from "@/provider/analytics"; +import { getAnalyticsProposalInfo } from "@/utils/analytics"; interface TableProps { proposals: Proposal[]; + isMobile: boolean; } const PAGE_SIZE = 10; @@ -22,11 +25,14 @@ enum ProposalFilter { REJECTED = "REJECTED PROPOSALS", } -const ProposalTable = ({ proposals }: TableProps) => { +const ProposalTable = ({ proposals, isMobile }: TableProps) => { // route to proposal page const router = useRouter(); const handleRowClick = (proposalId: any) => { // Navigate to the appropriate page + Analytics.actions.events.governance.proposalClicked( + getAnalyticsProposalInfo(proposalId, proposals) + ); router.push(`/governance/proposal?id=${proposalId}`); }; @@ -85,15 +91,18 @@ const ProposalTable = ({ proposals }: TableProps) => { { value: "", ratio: 2, + hideOnMobile: true, }, { value: "", ratio: 2, + hideOnMobile: true, }, { value: "", ratio: 1, + hideOnMobile: true, }, ]; return ( @@ -117,9 +126,9 @@ const ProposalTable = ({ proposals }: TableProps) => { : undefined } removeHeader={true} - rowHeight="120px" + rowHeight={isMobile ? "180px" : "120px"} content={activeProposals.map((proposal) => - ProposalRow({ proposal, active: true }) + ProposalRow({ proposal, active: true, isMobile }) )} /> } @@ -133,7 +142,13 @@ const ProposalTable = ({ proposals }: TableProps) => { />
- There are currently no active proposals + {isMobile ? ( + There are no active proposals + ) : ( + + There are currently no active proposals + + )}
)} @@ -143,9 +158,20 @@ const ProposalTable = ({ proposals }: TableProps) => {
{ + {currentFilter} + + ) + } secondary={ - + filter.split(" ")[0] @@ -155,6 +181,7 @@ const ProposalTable = ({ proposals }: TableProps) => { const proposalFilter = Object.values(ProposalFilter).find( (filter) => filter.split(" ")[0] === value ); + Analytics.actions.events.governance.tabSwitched(value); setCurrentFilter(proposalFilter || ProposalFilter.ALL); }} /> @@ -174,7 +201,7 @@ const ProposalTable = ({ proposals }: TableProps) => { : undefined } removeHeader={true} - rowHeight="120px" + rowHeight={isMobile ? "180px" : "120px"} content={ paginatedProposals.length > 0 ? [ @@ -184,9 +211,10 @@ const ProposalTable = ({ proposals }: TableProps) => { proposal.status != "PROPOSAL_STATUS_VOTING_PERIOD" ) .map((proposal) => - ProposalRow({ proposal, active: false }) + ProposalRow({ proposal, active: false, isMobile }) ), -
+
diff --git a/app/governance/components/votingChart/voteGraph.module.scss b/app/governance/components/votingChart/voteGraph.module.scss index 6c93f823..99b7c888 100644 --- a/app/governance/components/votingChart/voteGraph.module.scss +++ b/app/governance/components/votingChart/voteGraph.module.scss @@ -17,46 +17,48 @@ justify-content: space-around; margin: 20px 20px 20px 20px; border-bottom: 1px solid var(--border-stroke-color, #b3b3b3); - .graph { - cursor: auto; - width: 30px; - margin-right: 30px; - margin-left: 30px; - border-radius: 5px 5px 0 0; - background-color: var(--graph-fill-color, #d0d0d0); - border: 1px solid var(--graph-stroke-color, #b3b3b3); - border-bottom: none; - //border-bottom: 1px solid var(--border-stroke-color, #b3b3b3); - } - .voteInfo { + .barContainer { display: flex; - flex-direction: row; - justify-content: center; + flex-direction: column-reverse; + + align-items: center; + width: 25%; + .bar { + cursor: auto; + margin-right: 30px; + margin-left: 30px; + border-radius: 5px 5px 0 0; + background-color: var(--graph-fill-color, #d0d0d0); + border: 1px solid var(--graph-stroke-color, #b3b3b3); + border-bottom: none; + } + .amountInfo { + display: flex; + flex-direction: row; + justify-content: center; + align-items: center; + align-content: center; + margin-bottom: 20px; + padding: 4px; + width: fit-content; + border-radius: 2px; + background-color: var(--graph-fill-color, #d0d0d0); + .icon { + display: flex; + flex-direction: column; + justify-content: center; + padding-left: 2px; + } } - .amountInfo { + + .voteInfo { display: flex; flex-direction: row; justify-content: center; - margin-bottom: 20px; - padding: 5px 5px 5px 5px; - width: 90px; - //padding: 5px; - border-radius: 2px; - background-color: var(--graph-fill-color, #d0d0d0); - .icon { - display: flex; - flex-direction: column; - justify-content: center; - padding-left: 2px; - } } - .barContainer { - display: flex; - flex-direction: column-reverse; - //height: 60%; - width: 25%; - //padding-right: 5%; + } + } .inforow { @@ -67,7 +69,7 @@ .voteOption { display: flex; flex-direction: row; - justify-content: left; + justify-content: center; width: 25%; //margin-right: 5%; diff --git a/app/governance/components/votingChart/voteGraph.tsx b/app/governance/components/votingChart/voteGraph.tsx index 07bd6af2..19cd834d 100644 --- a/app/governance/components/votingChart/voteGraph.tsx +++ b/app/governance/components/votingChart/voteGraph.tsx @@ -11,15 +11,17 @@ interface VoteBarGraphProps { abstain: number; veto: number; size: number; + isMobile?: boolean; } interface BarProps { amount: number; totalVotes: number; size: number; + isMobile?: boolean; } -const Bar = ({ amount, totalVotes, size }: BarProps) => { +const Bar = ({ amount, totalVotes, size, isMobile }: BarProps) => { const height = ((totalVotes > 0 ? (amount / totalVotes) * 100 : 0) * size) / 150; //150 is to make the bar occupy at max 2/3rd of the total height of the container if an option get 100% votes @@ -28,9 +30,10 @@ const Bar = ({ amount, totalVotes, size }: BarProps) => { {/*
YES
*/} {height > 0 && (
)} @@ -45,10 +48,7 @@ const Bar = ({ amount, totalVotes, size }: BarProps) => { @@ -68,21 +68,36 @@ const VoteInfo = ({ color, percentage, name, + isMobile, }: { color: string; percentage: number; name: string; + isMobile?: boolean; }) => { return (
-
-
-
-
- - {name} ({percentage.toFixed(1)}%) - -
+ + +
+
+
+ + {name} + {" "} + + + + ({percentage.toFixed(1)}%) + + +
); }; @@ -92,6 +107,7 @@ export const VoteBarGraph = ({ abstain, veto, size, + isMobile, }: VoteBarGraphProps) => { const totalVotes = yes + no + abstain + veto; @@ -101,31 +117,55 @@ export const VoteBarGraph = ({ Voting Stats
- - - - + + + +
0 ? (yes / totalVotes) * 100 : 0} name="YES" color="#0DFE17" + isMobile={isMobile} /> 0 ? (no / totalVotes) * 100 : 0} name="NO" color="#EF4444" + isMobile={isMobile} /> 0 ? (veto / totalVotes) * 100 : 0} name="VETO" color="#9747FF" + isMobile={isMobile} /> 0 ? (abstain / totalVotes) * 100 : 0} name="ABSTAIN" color="#EAD42A" + isMobile={isMobile} />
@@ -174,7 +214,13 @@ export const VoteBarSecondary = ({ ); }; -export const VoteGraphBox = ({ yes, no, abstain, veto }: VoteBarGraphProps) => { +export const VoteGraphBox = ({ + yes, + no, + abstain, + veto, + isMobile, +}: VoteBarGraphProps) => { const totalVotes = yes + no + abstain + veto; const yesPercentage = totalVotes > 0 ? (yes / totalVotes) * 100 : 0; diff --git a/app/governance/gov.module.scss b/app/governance/gov.module.scss index 4fa8aa1a..fff6a750 100644 --- a/app/governance/gov.module.scss +++ b/app/governance/gov.module.scss @@ -20,49 +20,35 @@ } } -.active { - opacity: 1; - position: relative; - &::before { - content: ""; - top: 0; - right: 0; - display: block; - position: absolute; - width: 10px; - transform: translate(20%, -80%) scale(1, 1); - height: 10px; - border-right: 2px solid var(--primary-dark-color); - border-top: 2px solid var(--primary-dark-color); - } - &::after { - position: absolute; - bottom: 0; - left: 0; - content: ""; - display: block; - width: 10px; - transform: translate(-20%, 90%) scale(1, 1); - height: 10px; - border-left: 2px solid var(--primary-dark-color); - border-bottom: 2px solid var(--primary-dark-color); - } + + +.title { + font-size: 32px !important; + text-align: left; +} +.middleText { + padding: 10px 16px 10px 16px; + background-color: var(--card-surface-color, #f1f1f1); } -.header { - display: flex; - direction: row !important; - justify-content: space-between; - width: 100% !important; - //align-items: center; - .title { - font-size: 32px !important; - text-align: left; - width: 50%; +@media screen and (max-width: 768px) { + .container { + border-top: 1px solid var(--border-stroke-color,#b3b3b3); + width: calc(100vw); + //gap: 1rem; + padding: 1rem; + &::after { + display: none; + } + &::before { + display: none; + } } - .middleText { - padding: 10px 16px 10px 16px; - background-color: var(--card-surface-color, #f1f1f1); + .header{ + // justify-content: space-between; + // width: 100%; } + + } diff --git a/app/governance/page.tsx b/app/governance/page.tsx index 57ffdbc8..1d9a7254 100644 --- a/app/governance/page.tsx +++ b/app/governance/page.tsx @@ -12,11 +12,15 @@ import useCantoSigner from "@/hooks/helpers/useCantoSigner"; import Splash from "@/components/splash/splash"; import Link from "next/link"; import Container from "@/components/container/container"; +import useScreenSize from "@/hooks/helpers/useScreenSize"; export default function GovernancePage() { const { chainId } = useCantoSigner(); + const { isMobile } = useScreenSize(); const { proposals, isProposalsLoading } = useProposals({ chainId: chainId }); + //console.log(isMobile); + const sorted_proposals = useMemo( () => proposals.sort( @@ -31,24 +35,32 @@ export default function GovernancePage() { ) : (
-
- - Governance - + +
+ + Governance + +
- Stake your $CANTO to participate in governance + Stake {isMobile ? "" : "your"} $CANTO to participate in governance -
+ - + - +
diff --git a/app/governance/proposal/page.tsx b/app/governance/proposal/page.tsx index a7f47008..c1eff677 100644 --- a/app/governance/proposal/page.tsx +++ b/app/governance/proposal/page.tsx @@ -26,6 +26,8 @@ import { import Spacer from "@/components/layout/spacer"; import useStaking from "@/hooks/staking/useStaking"; import { VoteBarGraph } from "../components/votingChart/voteGraph"; +import useScreenSize from "@/hooks/helpers/useScreenSize"; +import Container from "@/components/container/container"; const VOTE_OPTION_COLORS = { [VoteOption.YES]: [ @@ -58,6 +60,7 @@ export default function Page() { chainId: chainId, userEthAddress: signer?.account.address, }); + const { isMobile } = useScreenSize(); // transaction function castVote(proposalId: number, voteOption: VoteOption | null) { if (signer) { @@ -68,6 +71,7 @@ export default function Page() { chainId: chainId, ethAccount: signer.account.address, proposalId: proposalId, + proposal: proposals.find((p) => p.proposal_id === Number(proposalId)), voteOption: voteOption, }); txStore?.addNewFlow({ @@ -127,7 +131,7 @@ export default function Page() { return isProposalsLoading ? ( ) : ( -
+
)}
-
+
{proposal.title} @@ -187,45 +196,72 @@ export default function Page() {
-
+
{isActive && ( -
+
Select an option to vote
-
- - -
+ + + {" "} + + + {" "} + + -
- - -
+ + + {" "} + + + {" "} + + -
+
-
+ + {/* {isMobile && ( +
+ {" "} + {" "} + {" "} + +
+ )} */}
)} -
- -
- +
-
+
Proposal Details
-
- +
+ Type
- + {formatProposalType(proposal.type_url)}
-
- +
+ Veto
- + {PROPOSAL_VETO_THRESHOLD} - {/*
- -
*/}
-
- +
+ Quorum{" "}
- + {PROPOSAL_QUORUM_VALUE}
- + Voting Timeline
@@ -317,12 +371,12 @@ export default function Page() {
- - Proposal Created on + + Created on
- + {formatTime(proposal.submit_time)}
@@ -333,12 +387,12 @@ export default function Page() {
- + Voting Ended on{" "}
- + {formatTime(proposal.voting_end_time)}
diff --git a/app/governance/proposal/proposalModal.module.scss b/app/governance/proposal/proposalModal.module.scss index c25e3b3d..0b322f8d 100644 --- a/app/governance/proposal/proposalModal.module.scss +++ b/app/governance/proposal/proposalModal.module.scss @@ -1,8 +1,8 @@ -.proposalContainer { +.container { display: flex; flex-direction: column; align-items: center; - max-width: 1400px !important; + max-width: 1200px !important; margin: 10px auto; border-top: 1px solid var(--primary-90-color); position: relative; @@ -52,25 +52,25 @@ } .proposalInfoContainer { padding: 10px 0px 0px 0px; - display: flex !important; - flex-direction: row !important; + display: flex ; + flex-direction: row ; width: 100%; margin: 0 20px 0 20px; .graphAndVoteContainer { - width: 70%; - min-width: 500px; + //min-width: 500px; display: flex; flex-direction: column; margin-right: 20px; - .proposalCardContainer1 { + .votingOptionsContainer { display: flex; flex-direction: column !important; justify-content: space-between; border: 1px solid var(--border-stroke-color, #b3b3b3); background-color: var(--card-sub-surface-color, #dfdfdf); box-shadow: var(--box-shadow, 3px 3px 0px 0px rgba(17, 17, 17, 0.15)); - height: 360px; + //width: 100%; + //height: 360px; margin-top: 30px; .detailsHeader { width: 100%; @@ -92,18 +92,6 @@ .proposalInfoVoting:hover { background-color: #afe0cc; } - .proposalInfoRow1 { - display: flex; - flex-direction: row !important; - justify-content: space-between; - height: 33%; - padding: 15px 30px 0px 30px; - .radioBtnContainer { - display: flex; - align-items: center; - margin: 0px 17px 0px 15px; - } - } .votingInfoRow1 { display: flex; flex-direction: row; @@ -184,15 +172,14 @@ height: 500px; display: flex; flex-direction: column !important; - margin-top: 30px; - min-width: 400px; - width: 30%; + //min-width: 400px; + //width: 30%; border: 1px solid var(--border-stroke-color, #b3b3b3); box-shadow: var(--box-shadow, 3px 3px 0px 0px rgba(17, 17, 17, 0.15)); background-color: var(--card-sub-surface-color, #dfdfdf); .detailsHeader { width: 100%; - padding: 20px 0px 20px 20px; + padding: 16px; border-bottom: 1px solid var(--border-stroke-color, #b3b3b3); } @@ -238,7 +225,7 @@ } } .separator { - height: 5rem; + height: 3rem; //padding-left: 60px; margin-left: 4px; border-left: 2px solid var(--graph-fill-color, #d0d0d0); @@ -283,3 +270,32 @@ height: 100%; justify-self: center; } + +@media screen and (max-width: 768px) { + .container { + border-top: 1px solid var(--border-stroke-color,#b3b3b3); + width: calc(100vw); + //gap: 1rem; + padding: 1rem; + &::after { + display: none; + } + &::before { + display: none; + } + .proposalInfoContainer { + padding: 10px 0px 0px 0px; + display: flex; + flex-direction: column; + width: 100%; + margin: 0 20px 0 20px; + } + } + + .header{ + // justify-content: space-between; + // width: 100%; + } + + +} \ No newline at end of file diff --git a/app/lp/components/ambient/managePosition.tsx b/app/lp/components/ambient/managePosition.tsx index 9d24d3e6..b501a46c 100644 --- a/app/lp/components/ambient/managePosition.tsx +++ b/app/lp/components/ambient/managePosition.tsx @@ -156,6 +156,12 @@ const AddLiquidity = ({ min="0" max={pool.base.balance ?? "0"} symbol={pool.base.symbol} + ambientAmountError={ + Number(pool.stats.lastPriceSwap) <= + Number( + positionManager.getWeiRangePrice(positionValues.lowerPrice) + ) && Number(amountBase) !== 0 + } /> = + Number( + positionManager.getWeiRangePrice(positionValues.upperPrice) + ) && Number(amountQuote) !== 0 + } /> diff --git a/app/lp/components/ambient/newAmbientPosition.tsx b/app/lp/components/ambient/newAmbientPosition.tsx index b79aa218..d85eed70 100644 --- a/app/lp/components/ambient/newAmbientPosition.tsx +++ b/app/lp/components/ambient/newAmbientPosition.tsx @@ -29,6 +29,7 @@ import { } from "@/utils/ambient/liquidityControllers"; import { Validation } from "@/config/interfaces"; import Analytics from "@/provider/analytics"; +import BigNumber from "bignumber.js"; import useScreenSize from "@/hooks/helpers/useScreenSize"; interface NewPositionModalProps { pool: AmbientPool; @@ -83,6 +84,11 @@ export const NewAmbientPositionModal = ({ const percentDiff = (currentPrice: number, selectedPrice: number) => formatPercent(((selectedPrice - currentPrice) / currentPrice).toString()); + function getWeiRangePrice(priceFormatted: string): string { + const scale = BigNumber(10).pow(pool.base.decimals - pool.quote.decimals); + const priceWei = scale.multipliedBy(priceFormatted).toString(); + return priceWei; + } const { isMobile } = useScreenSize(); return ( = + Number( + getWeiRangePrice(positionManager.options.maxRangePrice) + ) && Number(positionManager.options.amountQuote) !== 0 + } /> diff --git a/app/lp/components/dexModals/AddLiquidityModal.tsx b/app/lp/components/dexModals/AddLiquidityModal.tsx index c5c182a8..a42bb230 100644 --- a/app/lp/components/dexModals/AddLiquidityModal.tsx +++ b/app/lp/components/dexModals/AddLiquidityModal.tsx @@ -18,6 +18,7 @@ import Toggle from "@/components/toggle"; import { areEqualAddresses } from "@/utils/address"; import PopUp from "@/components/popup/popup"; import { CantoDexTxTypes } from "@/transactions/pairs/cantoDex"; +import BigNumber from "bignumber.js"; interface AddLiquidityProps { pair: CantoDexPairWithUserCTokenData; @@ -91,6 +92,23 @@ export const AddLiquidityModal = ({ : token.symbol; }; + // function to get max input amount + const tokenBalance = (token: { + chainId: number; + address: string; + balance?: string; + }) => { + const updatedBalance = BigNumber(token.balance ?? "0").minus( + "1000000000000000000" + ); + const wcantoAddress = getCantoCoreAddress(Number(token.chainId), "wcanto"); + return areEqualAddresses(token.address, wcantoAddress ?? "") + ? updatedBalance.isNegative() + ? "0" + : updatedBalance.toString() + : token.balance ?? "0"; + }; + return (
@@ -107,7 +125,7 @@ export const AddLiquidityModal = ({ IconUrl={pair.token1.logoURI} title={tokenSymbol(pair.token1)} min="1" - max={pair.token1.balance ?? "0"} + max={tokenBalance(pair.token1)} maxName="LP Modal" symbol={tokenSymbol(pair.token1)} /> @@ -121,7 +139,7 @@ export const AddLiquidityModal = ({ IconUrl={pair.token2.logoURI} title={tokenSymbol(pair.token2)} min="1" - max={pair.token2.balance ?? "0"} + max={tokenBalance(pair.token2)} maxName="LP Modal" symbol={tokenSymbol(pair.token2)} /> diff --git a/app/lp/components/pairRow.tsx b/app/lp/components/pairRow.tsx index 032aa39d..c0f8bc5a 100644 --- a/app/lp/components/pairRow.tsx +++ b/app/lp/components/pairRow.tsx @@ -50,7 +50,7 @@ export const UserCantoDexPairRow = ({ - + {pair.symbol} @@ -193,7 +193,7 @@ export const GeneralCantoDexPairRow = ({ - + {pair.symbol} @@ -252,7 +252,7 @@ export const GeneralAmbientPairRow = ({ - + {pool.symbol} @@ -380,7 +380,7 @@ export const UserAmbientPairRow = ({ - + {pool.symbol} diff --git a/app/lp/page.tsx b/app/lp/page.tsx index 7e1a37f4..0f7dadee 100644 --- a/app/lp/page.tsx +++ b/app/lp/page.tsx @@ -163,7 +163,10 @@ export default function Page() { //@ts-ignore title={pairNames[filteredPairs]} secondary={ - + void + onDelegate: (validator: Validator) => void, + isMobile: boolean ) => [ - - {validator.rank} - , - -
- {validator.description.moniker} + !isMobile && ( + + {validator.rank} + + ), + +
+ + {validator.description.moniker} +
, {displayAmount(validator.tokens, 18)}
@@ -46,25 +66,28 @@ export const GenerateValidatorTableRow = ( {displayAmount(validator.commission, -2, { precision: 2 })}%
, - - - , + !isMobile && ( + + + + ), ]; export const GenerateMyStakingTableRow = ( userStakedValidator: ValidatorWithDelegations, index: number, - onDelegate: (validator: Validator) => void + onDelegate: (validator: Validator) => void, + isMobile: boolean ) => [ {userStakedValidator?.description.moniker} @@ -90,25 +113,27 @@ export const GenerateMyStakingTableRow = ( themed={true} /> , - - - {displayAmount(userStakedValidator?.tokens, 18, {})} - -
- -
, + !isMobile && ( + + + {displayAmount(userStakedValidator?.tokens, 18, {})} + +
+ +
+ ), {displayAmount(userStakedValidator?.commission, -2, { @@ -117,21 +142,23 @@ export const GenerateMyStakingTableRow = ( % , - - - , + !isMobile && ( + + + + ), ]; export const GenerateUnbondingDelegationsTableRow = ( diff --git a/app/staking/page.tsx b/app/staking/page.tsx index b95db17a..92b9e3b2 100644 --- a/app/staking/page.tsx +++ b/app/staking/page.tsx @@ -19,7 +19,7 @@ import { GenerateMyStakingTableRow, GenerateUnbondingDelegationsTableRow, GenerateValidatorTableRow, -} from "./components/validatorTableRow"; +} from "./components/tableRows"; import { useMemo, useState } from "react"; import { StakingModal } from "./components/stakingModal/StakingModal"; import { Validator } from "@/hooks/staking/interfaces/validators"; @@ -37,7 +37,8 @@ import { Pagination } from "@/components/pagination/Pagination"; import { levenshteinDistance } from "@/utils/staking/searchUtils"; import { WalletClient } from "wagmi"; import Analytics from "@/provider/analytics"; -import clsx from "clsx"; +import useScreenSize from "@/hooks/helpers/useScreenSize"; +import { getAnalyticsStakingInfo } from "@/utils/analytics"; export default function StakingPage() { // connected user info @@ -49,7 +50,7 @@ export default function StakingPage() { chainId: chainId, userEthAddress: signer?.account.address, }); - + const { isMobile } = useScreenSize(); // handle txs function handleRewardsClaimClick( signer: GetWalletClientResult | undefined, @@ -265,6 +266,7 @@ export default function StakingPage() { return isLoading ? ( ) : ( + //main content
@@ -273,7 +275,11 @@ export default function StakingPage() { STAKING - + {userStaking && userStaking.unbonding.length > 0 && (
+ Number(formatBalance(e.userDelegation.balance, 18)) > + 0.0000001 + ) + .sort((a, b) => + b.userDelegation.balance.localeCompare( + a.userDelegation.balance + ) + ) + .map((validator) => () => handleClick(validator)) + : undefined + } headers={[ { value: "Name", @@ -319,6 +341,7 @@ export default function StakingPage() { { value: "Total Stake", ratio: 3, + hideOnMobile: true, }, { value: "Commission", @@ -327,6 +350,7 @@ export default function StakingPage() { { value:
, ratio: 3, + hideOnMobile: true, }, ]} content={[ @@ -342,33 +366,75 @@ export default function StakingPage() { ) ) .map((userStakingElement, index) => - GenerateMyStakingTableRow(userStakingElement, index, () => - handleClick(userStakingElement) + GenerateMyStakingTableRow( + userStakingElement, + index, + () => handleClick(userStakingElement), + isMobile ) ), ]} /> )} + {/* {isMobile && ( + + { + Analytics.actions.events.staking.tabSwitched(value); + setCurrentFilter(value); + setCurrentPage(1); + setSearchQuery(""); + }} + /> + + )} */} {validators.length > 0 && (
+ VALIDATORS + + } + onRowsClick={ + isMobile + ? currentFilter == "ACTIVE" + ? paginatedvalidators.map( + (validator) => () => handleClick(validator) + ) + : undefined + : undefined + } secondary={ - setSearchQuery(e.target.value)} - placeholder={"Search..."} - /> - + + setSearchQuery(e.target.value)} + placeholder={"Search..."} + /> + + + + Name + + ), + ratio: isMobile ? 5 : 6, }, { value: "Total Stake", @@ -403,17 +482,22 @@ export default function StakingPage() { { value:
, ratio: 4, + hideOnMobile: true, }, ]} content={ paginatedvalidators.length > 0 ? [ ...paginatedvalidators.map((validator, index) => - GenerateValidatorTableRow(validator, index, () => - handleClick(validator) + GenerateValidatorTableRow( + validator, + index, + () => handleClick(validator), + isMobile ) ), )} - - -
-
- Total Staked -
- -
- - {displayAmount( - totalStaked ? totalStaked.toFixed(2) : "0", - 0 - )} + + {isMobile && ( +
+ +
+ )} + + + + + + Staking Stats{" "} + + + +
+
+ + Rewards
-

- - -
-
-
- APR -
- - - {formatPercent((parseFloat(apr) / 100).toString())} - - -
-
-
- Rewards + + +
+ + {totalRewards?.toFixed(5)}{" "} + + +
+
- -
- - {totalRewards?.toFixed(5)}{" "} - - + +
+
+ + APR + +
+ + + {formatPercent((parseFloat(apr) / 100).toString())} + + +
+
+
+ + Total Staked{" "} + +
+ + +
+ + {displayAmount( + totalStaked ? totalStaked.toFixed(2) : "0", + 0 + )} + +
+

+
-
-
- - + + + + +
diff --git a/app/staking/staking.module.scss b/app/staking/staking.module.scss index 0bd80ccd..6822578b 100644 --- a/app/staking/staking.module.scss +++ b/app/staking/staking.module.scss @@ -26,22 +26,43 @@ } .infoCard { - background: var(--card-sub-surface-color, #dfdfdf); + //background: green; box-shadow: 6px 6px 0px 0px rgba(17, 17, 17, 0.15); border: 1px solid var(--border-stroke-color); display: flex; flex-direction: column; height: 400px; - padding: 24px; - position: sticky; + //padding: 24px; top: 20px; margin-top: 0; - width: 340px; .infoBox { display: flex; flex-direction: column; - height: 25%; - margin-top: 12px; - margin-bottom: 12px; + //height: 25%; + margin-top: 8px; + margin-bottom: 8px; } } + +@media screen and (max-width: 768px) { + .container { + border-top: 1px solid var(--border-stroke-color,#b3b3b3); + width: calc(100vw); + //gap: 1rem; + padding: 1rem; + &::after { + display: none; + } + &::before { + display: none; + } + } + // .infoBox{ + // display: flex; + // flex-direction: column; + // height: 25%; + // margin-top: 12px; + // margin-bottom: 12px; + // background-color: var(--card-primary-color, #111111); + // } +} diff --git a/components/amount/amount.tsx b/components/amount/amount.tsx index 6f27aa1f..d1b89d2f 100644 --- a/components/amount/amount.tsx +++ b/components/amount/amount.tsx @@ -8,6 +8,8 @@ import clsx from "clsx"; import Spacer from "../layout/spacer"; import { validateNonWeiUserInputTokenAmount } from "@/utils/math"; import Analytics from "@/provider/analytics"; +import { TX_PARAM_ERRORS } from "@/config/consts/errors"; + interface Props { IconUrl: string; title: string; @@ -23,6 +25,7 @@ interface Props { }; extraNode?: React.ReactNode; maxName?: string; + ambientAmountError?: boolean; } const Amount = (props: Props) => { const [focused, setFocused] = useState(false); @@ -74,13 +77,15 @@ const Amount = (props: Props) => { // deal with error inputs const inputError = useMemo( () => - validateNonWeiUserInputTokenAmount( - props.value, - props.min, - props.limit?.limit ?? props.max, - props.symbol, - props.decimals - ), + !props.ambientAmountError + ? validateNonWeiUserInputTokenAmount( + props.value, + props.min, + props.limit?.limit ?? props.max, + props.symbol, + props.decimals + ) + : { error: true, reason: TX_PARAM_ERRORS.AMBIENT_AMOUNT_ERROR() }, [ props.value, props.max, @@ -88,6 +93,7 @@ const Amount = (props: Props) => { props.decimals, props.symbol, props.limit?.limit, + props.ambientAmountError, ] ); diff --git a/components/button/button.tsx b/components/button/button.tsx index d60c2dc3..3c8a07e6 100644 --- a/components/button/button.tsx +++ b/components/button/button.tsx @@ -20,6 +20,7 @@ export interface ButtonProps { disabled?: boolean; shadow?: "small" | "medium" | "none"; buttonProps?: React.JSX.IntrinsicElements["button"]; + themed?: boolean; } const Button = (props: ButtonProps) => { @@ -62,15 +63,35 @@ const Button = (props: ButtonProps) => { const getBGColor = () => { if (props.disabled) { - return "var(--primary-10-color)"; + if (props.themed || props.themed == undefined) { + return "var(--primary-10-color)"; + } + switch (props.color) { + case "primary": + return "#111111"; + case "secondary": + return "#f1f1f1"; + case "accent": + return "#06fc99"; + case undefined: + return "var(--primary-10-color)"; + default: + return "var(--primary-10-color)"; + } } switch (props.color) { case "primary": - return "var(--text-dark-color)"; + return props.themed || props.themed == undefined + ? "var(--text-dark-color)" + : "#111111"; case "secondary": - return "var(--card-surface-color)"; + return props.themed || props.themed == undefined + ? "var(--card-surface-color)" + : "#f1f1f1"; case "accent": - return "var(--extra-success-color)"; + return props.themed || props.themed == undefined + ? "var(--extra-success-color)" + : "#06fc99"; case undefined: return "var(--text-dark-color)"; default: @@ -80,15 +101,35 @@ const Button = (props: ButtonProps) => { const getTextColor = () => { if (props.disabled) { - return "var(--text-dark-40-color)"; + if (props.themed || props.themed == undefined) { + return "var(--primary-10-color)"; + } + switch (props.color) { + case "primary": + return "rgb(#f1f1f1)"; + case "secondary": + return "rgb(#111111)"; + case "accent": + return "rgb(#212121)"; + case undefined: + return "var(--primary-10-color)"; + default: + return "var(--primary-10-color)"; + } } switch (props.color) { case "primary": - return "var(--text-light-color)"; + return props.themed || props.themed == undefined + ? "var(--text-light-color)" + : "#ffffff"; case "secondary": - return "var(--text-dark-color)"; + return props.themed || props.themed == undefined + ? "var(--text-dark-color)" + : "#111111"; case "accent": - return "var(--text-only-dark)"; + return props.themed || props.themed == undefined + ? "var(--text-only-dark)" + : "#212121"; case undefined: return "var(--text-light-color)"; default: diff --git a/components/nav_bar/navBar.tsx b/components/nav_bar/navBar.tsx index e654516d..298a59de 100644 --- a/components/nav_bar/navBar.tsx +++ b/components/nav_bar/navBar.tsx @@ -14,11 +14,13 @@ import useCantoSigner from "@/hooks/helpers/useCantoSigner"; import { useBalance } from "wagmi"; import { useAutoConnect } from "@/provider/useAutoConnect"; import Icon from "../icon/icon"; +import useScreenSize from "@/hooks/helpers/useScreenSize"; const NavBar = () => { // This is used to connect safe as wallet, // if the app is opened in the safe context. useAutoConnect(); + const { isMobile } = useScreenSize(); const currentPath = usePathname(); const searchParams = useSearchParams(); const { signer } = useCantoSigner(); @@ -126,7 +128,7 @@ const NavBar = () => { Pools { > Explore - {/* {currentPath == "/staking" && ( + {isMobile && ( Analytics.actions.events.clickedNavLink("Staking")} > Staking )} - {(currentPath == "/governance" || - currentPath == "/governance/proposal") && ( + {isMobile && ( Analytics.actions.events.clickedNavLink("Governance") } > Governance - )} */} -
setIsMoreModalOpen(true)} - onMouseLeave={() => setIsMoreModalOpen(false)} - > -
- More -
- -
-
- {isMoreModalOpen && ( -
- { - { - setIsMoreModalOpen(false); - Analytics.actions.events.clickedNavLink("Staking"); - }} - > -
- Staking -
- - } - { - { - setIsMoreModalOpen(false); - Analytics.actions.events.clickedNavLink("Governance"); + )} + {!isMobile && ( +
setIsMoreModalOpen(true)} + onMouseLeave={() => setIsMoreModalOpen(false)} + > +
+ More +
+ -
- Governance -
- - } + themed + /> +
- )} -
+ {isMoreModalOpen && ( +
+ { + { + setIsMoreModalOpen(false); + Analytics.actions.events.clickedNavLink("Staking"); + }} + > +
+ Staking +
+ + } + { + { + setIsMoreModalOpen(false); + Analytics.actions.events.clickedNavLink("Governance"); + }} + style={{ borderBottom: "none" }} + > +
+ Governance +
+ + } +
+ )} +
+ )}
diff --git a/components/pagination/Pagination.tsx b/components/pagination/Pagination.tsx index af6b7c6a..5bc16e65 100644 --- a/components/pagination/Pagination.tsx +++ b/components/pagination/Pagination.tsx @@ -6,6 +6,7 @@ interface Props { currentPage: number; totalPages: number; handlePageClick: (index: number) => void; + isMobile?: boolean; } export const Pagination = (props: Props) => { @@ -13,7 +14,7 @@ export const Pagination = (props: Props) => {
props.handlePageClick(1)} style={{ opacity: props.currentPage == 1 ? "0.4" : "1", @@ -29,7 +30,7 @@ export const Pagination = (props: Props) => { />
1 ? () => props.handlePageClick(props.currentPage - 1) @@ -47,62 +48,103 @@ export const Pagination = (props: Props) => { {" < "}
-
-
- {new Array(props.totalPages) - .fill(null) - .map((_, i) => i + 1) - .map((index) => { - return ( -
props.handlePageClick(index)} - > - + {!props.isMobile || props.totalPages < 6 ? ( +
+ {new Array(props.totalPages) + .fill(null) + .map((_, i) => i + 1) + .map((index) => { + return ( +
props.handlePageClick(index)} > - {index} - -
- ); - })} -
- {/*
- - {". . ."} - -
*/} - {/* { -
- {new Array(props.numbersToDisplay) - .fill(null) - .map( - (_, i) => - props.totalPages - (props.numbersToDisplay ?? 0) + (i + 1) - ) - .map((index) => { - return ( -
props.handlePageClick(index)} - style={getCurrentPageNumberStyle(index)} + - - {index} - -
- ); - })} + {index} + +
+ ); + })} +
+ ) : ( +
+ {props.currentPage >= props.totalPages - 1 && ( +
props.handlePageClick(1)} + > + + 1 + +
+ )} + {props.currentPage > 2 && ( +
+ + .. + +
+ )} + {props.currentPage > 1 && ( +
props.handlePageClick(props.currentPage - 1)} + > + + {props.currentPage - 1} + +
+ )} +
props.handlePageClick(props.currentPage)} + > + + {props.currentPage} +
- } */} + {props.currentPage < props.totalPages && ( +
props.handlePageClick(props.currentPage + 1)} + > + + {props.currentPage + 1} + +
+ )} + {props.currentPage < props.totalPages - 1 && ( +
+ + .. + +
+ )} + {props.currentPage <= 2 && ( +
props.handlePageClick(props.totalPages)} + > + + {props.totalPages} + +
+ )} +
+ )}
props.handlePageClick(props.currentPage + 1) @@ -121,7 +163,7 @@ export const Pagination = (props: Props) => {
props.handlePageClick(props.totalPages)} style={{ opacity: props.currentPage == props.totalPages ? "0.4" : "1", diff --git a/components/pagination/pagination.module.scss b/components/pagination/pagination.module.scss index 461ee461..1b86e9bf 100644 --- a/components/pagination/pagination.module.scss +++ b/components/pagination/pagination.module.scss @@ -6,9 +6,6 @@ height: 100%; border: "none"; padding: 16px 16px 0px 16px; - &:hover { - background: var(--card-sub-surface-color, #dfdfdf); - } } .row { display: flex; @@ -17,15 +14,17 @@ align-items: center; } -.iconContainer { +.icon { display: flex; flex-direction: column; justify-content: center; align-items: center; padding: 5px 10px 5px 10px; - &:hover { - background-color: var(--border-stroke-color, #b3b3b3); - z-index: 1; + @media screen and (min-width: 768px) { + &:hover { + background-color: var(--border-stroke-color, #b3b3b3); + z-index: 1; + } } } .numbers { @@ -40,19 +39,13 @@ align-items: center; padding: 5px 10px 5px 10px; cursor: pointer; - &:hover { - background-color: var(--border-stroke-color, #b3b3b3); - z-index: 1; - } -} -.button { - display: flex; - flex-direction: column; - justify-content: center; - align-items: center; - padding: 5px 10px 5px 10px; - &:hover { - background-color: var(--border-stroke-color, #b3b3b3); - z-index: 1; + @media screen and (min-width: 768px) { + &:hover { + background-color: var(--border-stroke-color, #b3b3b3); + z-index: 1; + } } } + + + diff --git a/components/table/table.module.scss b/components/table/table.module.scss index 618f557c..00f8fc87 100644 --- a/components/table/table.module.scss +++ b/components/table/table.module.scss @@ -99,28 +99,32 @@ } } } - .header, - .row { - height: 80px !important; + .header { width: 100% !important; } - - .table { - grid-template-rows: 80px 1fr; + .row { + height: 80px; + width: 100% !important; } + .container { padding: 0px; margin: 0px; min-width: 0px !important; } - + .tableTitle{ + padding-bottom: 1rem; + + } .title { align-items: center; - flex-wrap: wrap; + flex-direction: column; + align-items: flex-start; height: auto; + padding-top: 1rem; + padding-left: 0.5rem; + padding-right: 0.5rem; } - .primaryTitle{ - padding:0.5rem; - } + } diff --git a/components/table/table.tsx b/components/table/table.tsx index f7a333fe..8d99b9cc 100644 --- a/components/table/table.tsx +++ b/components/table/table.tsx @@ -27,8 +27,8 @@ const Table = (props: Props) => { {props.title} @@ -36,13 +36,13 @@ const Table = (props: Props) => {
{!props.removeHeader ? (
"Amount must be 0 in selected price range", }; export const TX_SIGN_ERRORS = { INCORRECT_TX_TYPE: (txType: string) => `Incorrect tx type ${txType}`, diff --git a/config/networks/canto/canto.ts b/config/networks/canto/canto.ts index d20e873f..9e142ea5 100644 --- a/config/networks/canto/canto.ts +++ b/config/networks/canto/canto.ts @@ -10,7 +10,7 @@ import { const cantoTestnetBlockExplorerEVM = "https://testnet.tuber.build"; const cantoMainBlockExplorerCosmos = "https://www.mintscan.io/canto"; -const cantoMainBlockExplorerEVM = "https://tuber.build"; +const cantoMainBlockExplorerEVM = "https://www.oklink.com/canto"; // canto will have an EVM and COSMOS chain data const cantoMainnetBaseInfo = { diff --git a/jest.config.mjs b/jest.config.mjs index cc895267..99008dbc 100644 --- a/jest.config.mjs +++ b/jest.config.mjs @@ -1,18 +1,17 @@ -import nextJest from 'next/jest.js' - +import nextJest from "next/jest.js"; + const createJestConfig = nextJest({ // Provide the path to your Next.js app to load next.config.js and .env files in your test environment - dir: './', -}) - + dir: "./", +}); + // Add any custom config to be passed to Jest /** @type {import('jest').Config} */ const config = { // Add more setup options before each test is run - // setupFilesAfterEnv: ['/jest.setup.js'], - - testEnvironment: 'jest-environment-jsdom', -} - + // setupFilesAfterEnv: ["/jest.setup.js"], + testEnvironment: "node", +}; + // createJestConfig is exported this way to ensure that next/jest can load the Next.js config which is async -export default createJestConfig(config) \ No newline at end of file +export default createJestConfig(config); diff --git a/provider/analytics.tsx b/provider/analytics.tsx index a3dd6e1d..8c582768 100644 --- a/provider/analytics.tsx +++ b/provider/analytics.tsx @@ -7,6 +7,7 @@ import { CTokenLendingTxTypes } from "@/transactions/lending"; import { CantoDexTxTypes } from "@/transactions/pairs/cantoDex"; import { AmbientTxType } from "@/transactions/pairs/ambient"; import { StakingTxTypes } from "@/transactions/staking"; +import { VoteOption } from "@/transactions/gov"; import posthog from "posthog-js"; // (BRIDGE/LP/LENDING/...) @@ -93,12 +94,19 @@ export type AnalyticsStakingData = { stakingNewValidator?: string; }; +export type AnalyticsGovernanceData = { + govProposalId?: Number, + govProposalTitle?: string, + govVoteOption?: VoteOption, +}; + export type AnalyticsTransactionFlowData = | AnalyticsBridgeData | AnalyticsCantoLPData | AnalyticsAmbientLPData | AnalyticsLMData - | AnalyticsStakingData; + | AnalyticsStakingData + | AnalyticsGovernanceData;; // tx types (approve/mint/swap/...) type AnalyticsTransactionType = CantoFETxType; @@ -239,6 +247,16 @@ class AnalyticsWrapper { }); }, }, + governance: { + proposalClicked: (params: AnalyticsGovernanceData) => { + posthog.capture("Proposal Clicked", params); + }, + tabSwitched: (tab: string) => { + posthog.capture("Proposal Tab Switched", { + tab, + }); + }, + }, transactionFlows: { started: (params: AnalyticsTransactionFlowParams) => { posthog.capture("Transaction Flow Started", params); diff --git a/transactions/gov/voteTxParams.ts b/transactions/gov/voteTxParams.ts index de892a4e..ace7c0db 100644 --- a/transactions/gov/voteTxParams.ts +++ b/transactions/gov/voteTxParams.ts @@ -1,8 +1,10 @@ +import { Proposal } from "@/hooks/gov/interfaces/proposal"; import { VoteOption } from "./voteOptions"; export interface ProposalVoteTxParams { chainId: number; ethAccount: string; proposalId: number; + proposal?: Proposal; voteOption: VoteOption; } diff --git a/transactions/pairs/ambient/ambientTx.ts b/transactions/pairs/ambient/ambientTx.ts index 33ebc3af..b4d9df29 100644 --- a/transactions/pairs/ambient/ambientTx.ts +++ b/transactions/pairs/ambient/ambientTx.ts @@ -210,6 +210,11 @@ export function validateAmbientLiquidityTxParams( getPriceFromTick(txParams.lowerTick), getPriceFromTick(txParams.upperTick) ); + + if(Number(currentPrice) <= Number(getPriceFromTick(txParams.lowerTick)) && Number(baseAmount) !== 0){ + return {error: true, reason: TX_PARAM_ERRORS.AMBIENT_AMOUNT_ERROR()} + } + const baseCheck = validateWeiUserInputTokenAmount( baseAmount, "0", @@ -228,6 +233,11 @@ export function validateAmbientLiquidityTxParams( getPriceFromTick(txParams.upperTick) ) : txParams.amount; + + if(Number(currentPrice) >= Number(getPriceFromTick(txParams.upperTick)) && Number(quoteAmount) !== 0){ + return {error: true, reason: TX_PARAM_ERRORS.AMBIENT_AMOUNT_ERROR()} + } + const quoteCheck = validateWeiUserInputTokenAmount( quoteAmount, "0", diff --git a/transactions/pairs/cantoDex/cantoDexTx.ts b/transactions/pairs/cantoDex/cantoDexTx.ts index 5c11cf32..b383094e 100644 --- a/transactions/pairs/cantoDex/cantoDexTx.ts +++ b/transactions/pairs/cantoDex/cantoDexTx.ts @@ -31,6 +31,7 @@ import { TransactionFlowType } from "@/transactions/flows"; import { CTokenLendingTxTypes, cTokenLendingTx } from "@/transactions/lending"; import { quoteRemoveLiquidity } from "@/utils/cantoDex"; import { getTokenBalance } from "@/utils/tokens"; +import BigNumber from "bignumber.js"; export async function cantoDexLPTx( txParams: CantoDexTransactionParams @@ -93,14 +94,14 @@ export function validateCantoDexLPTxParams( validateWeiUserInputTokenAmount( txParams.amounts.amount1, "1", - token1.balance ?? "0", + tokenBalance(token1), token1.symbol, token1.decimals ), validateWeiUserInputTokenAmount( txParams.amounts.amount2, "1", - token2.balance ?? "0", + tokenBalance(token2), token2.symbol, token2.decimals ), @@ -464,3 +465,17 @@ export async function stakeCantoDexLPTx( return NEW_ERROR("stakeCantoDexLPTx", err); } } + + +// function to get max input amount +const tokenBalance = (token: { + chainId: number; + address: string; + balance?: string; +}) => { + const updatedBalance = BigNumber(token.balance ?? "0").minus("1000000000000000000"); + const wcantoAddress = getCantoCoreAddress(Number(token.chainId), "wcanto"); + return areEqualAddresses(token.address, wcantoAddress ?? "") + ? updatedBalance.isNegative() ? "0" : updatedBalance.toString() + : token.balance ?? "0" +}; \ No newline at end of file diff --git a/utils/analytics/analytics.utils.ts b/utils/analytics/analytics.utils.ts index 3ca9fc4a..f595ead4 100644 --- a/utils/analytics/analytics.utils.ts +++ b/utils/analytics/analytics.utils.ts @@ -7,6 +7,7 @@ import { AnalyticsCantoLPData, AnalyticsLMData, AnalyticsStakingData, + AnalyticsGovernanceData, } from "@/provider/analytics"; import { BridgeTransactionParams } from "@/transactions/bridge/types"; import { @@ -38,9 +39,11 @@ import { StakingTxTypes, } from "@/transactions/staking"; import { Validator } from "@/hooks/staking/interfaces/validators"; +import { ProposalVoteTxParams } from "@/transactions/gov"; +import { Proposal } from "@/hooks/gov/interfaces/proposal"; export function displayAnalyticsAmount(amount: string, decimals: number) { - return displayAmount(amount, decimals, { short: false, precision: decimals }); + return displayAmount(amount, decimals, { short: false, precision: decimals < 0 ? 18 : decimals }); } export function getAnalyticsTransactionFlowInfo( @@ -84,6 +87,10 @@ export function getAnalyticsTransactionFlowInfo( txFlowInfo.txFlowType = flow.params.txType; txFlowInfo.txFlowData = getStakingTransactionFlowData(flow.params); break; + case TransactionFlowType.VOTE_TX: + txFlowInfo.txFlowType = "Vote"; + txFlowInfo.txFlowData = getProposalVoteTransactionFlowData(flow.params); + break; default: return NEW_ERROR("Invalid transaction flow type"); } @@ -386,6 +393,17 @@ function getStakingTransactionFlowData( } } + +function getProposalVoteTransactionFlowData( + voteTxParams: ProposalVoteTxParams +): AnalyticsTransactionFlowData { + return { + govProposalId: voteTxParams.proposalId, + govProposalTitle: voteTxParams.proposal?.title, + govVoteOption : voteTxParams.voteOption, + }; +} + function getLpComboClaimRewardsTransactionFlowType( lpComboClaimRewardsTxParams: ClaimDexComboRewardsParams ): string | undefined { @@ -498,3 +516,11 @@ export function getAnalyticsStakingInfo( stakingDelegation: displayAnalyticsAmount(delegation ?? "0", 18), }; } + +export function getAnalyticsProposalInfo(proposalId: any, proposals: Proposal[]) : AnalyticsGovernanceData { + const proposal = proposals.find((p) => p.proposal_id === Number(proposalId)); + return { + govProposalId: proposal?.proposal_id, + govProposalTitle: proposal?.title, + }; +} \ No newline at end of file