- {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