From e962534593998cd5a93471ead3dfc897ef1f1fc4 Mon Sep 17 00:00:00 2001
From: DaveVodrazka
Date: Sun, 16 Jun 2024 21:34:38 +0200
Subject: [PATCH 01/20] feat: basic layout
---
src/components/Vesting/Vest.tsx | 76 +++++++++++++++++++
src/components/Vesting/calls.ts | 7 ++
src/components/Vesting/index.ts | 3 +
src/components/Vesting/vest.module.css | 5 ++
.../WithdrawCapital/WithdrawParent.tsx | 5 +-
src/pages/governance.tsx | 12 ++-
6 files changed, 106 insertions(+), 2 deletions(-)
create mode 100644 src/components/Vesting/Vest.tsx
create mode 100644 src/components/Vesting/calls.ts
create mode 100644 src/components/Vesting/index.ts
create mode 100644 src/components/Vesting/vest.module.css
diff --git a/src/components/Vesting/Vest.tsx b/src/components/Vesting/Vest.tsx
new file mode 100644
index 00000000..1a026710
--- /dev/null
+++ b/src/components/Vesting/Vest.tsx
@@ -0,0 +1,76 @@
+import { AccountInterface } from "starknet";
+import { useAccount } from "../../hooks/useAccount";
+import { openWalletConnectDialog } from "../ConnectWallet/Button";
+import { unVestCarm, vestCarm } from "./calls";
+import { useEffect, useState } from "react";
+import { balanceOfCarmineToken } from "../../calls/balanceOf";
+import { Skeleton } from "@mui/material";
+import { shortInteger } from "../../utils/computations";
+import styles from "./vest.module.css";
+import inputStyles from "../../style/input.module.css";
+
+export const VestWithAccount = ({ account }: { account: AccountInterface }) => {
+ const [carmBalance, setCarmBalance] = useState(undefined);
+ const [inputValue, setInputValue] = useState("");
+
+ useEffect(() => {
+ balanceOfCarmineToken(account).then((b) =>
+ setCarmBalance(shortInteger(b, 18))
+ );
+ }, [account]);
+
+ if (carmBalance === undefined) {
+ return (
+
+
+
+
+ );
+ }
+
+ const handleInputChange = (value: string) => {
+ // Allow empty string, valid number, or a single decimal point followed by numbers
+ const numericValue =
+ value === "" || /^\d*\.?\d{0,6}$/.test(value) ? value : inputValue;
+
+ const num = parseFloat(numericValue);
+
+ if (num && num > carmBalance) {
+ // cannot set more than holds
+ return;
+ }
+
+ setInputValue(numericValue);
+ };
+
+ return (
+
+
+ You have 0 CARM and {carmBalance.toFixed(5)} veCarm
+
+
Stake your CARM for a period
+
+ handleInputChange(e.target.value)}
+ />
+
+
+
+
+
+ );
+};
+
+export const Vest = () => {
+ const account = useAccount();
+
+ if (!account) {
+ return ;
+ }
+
+ return ;
+};
diff --git a/src/components/Vesting/calls.ts b/src/components/Vesting/calls.ts
new file mode 100644
index 00000000..2e09329e
--- /dev/null
+++ b/src/components/Vesting/calls.ts
@@ -0,0 +1,7 @@
+export const vestCarm = () => {
+ console.log("Vesting...");
+};
+
+export const unVestCarm = () => {
+ console.log("UnVesting...");
+};
diff --git a/src/components/Vesting/index.ts b/src/components/Vesting/index.ts
new file mode 100644
index 00000000..090815a7
--- /dev/null
+++ b/src/components/Vesting/index.ts
@@ -0,0 +1,3 @@
+import { Vest } from "./Vest";
+
+export { Vest };
diff --git a/src/components/Vesting/vest.module.css b/src/components/Vesting/vest.module.css
new file mode 100644
index 00000000..aaa7ce95
--- /dev/null
+++ b/src/components/Vesting/vest.module.css
@@ -0,0 +1,5 @@
+.container {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+}
\ No newline at end of file
diff --git a/src/components/WithdrawCapital/WithdrawParent.tsx b/src/components/WithdrawCapital/WithdrawParent.tsx
index 238c24bb..38b44fcc 100644
--- a/src/components/WithdrawCapital/WithdrawParent.tsx
+++ b/src/components/WithdrawCapital/WithdrawParent.tsx
@@ -21,7 +21,10 @@ type Props = { address: string; account: AccountInterface };
const WithdrawParentWithAccount = ({ address, account }: Props) => {
const { isLoading, isError, isFetching, data } = useQuery(
- [QueryKeys.stake, address],
+ [
+ QueryKeys.stake,
+ "0x718505b87b5a448205ae22ac84a21b9e568b532ed95285c4c03973f8b1a73e8",
+ ],
fetchCapital
);
diff --git a/src/pages/governance.tsx b/src/pages/governance.tsx
index 3778ed39..7bf5b1f8 100644
--- a/src/pages/governance.tsx
+++ b/src/pages/governance.tsx
@@ -4,6 +4,7 @@ import { Helmet } from "react-helmet";
import { Layout } from "../components/Layout";
import { Proposals } from "../components/Proposal";
import { isMainnet } from "../constants/amm";
+import { Vest } from "../components/Vesting";
type Props = {
message: string;
@@ -45,7 +46,16 @@ const Governance = () => {
/>
{isMainnet ? (
-
+
+
CARM Staking
+
+ Stake your CARM
+
+
+
Proposals
+
Vote on AMM defining proposals
+
+
) : (
)}
From 11ef6725e9b2a283fe05cbf13ecaaea0aaa2d128 Mon Sep 17 00:00:00 2001
From: DaveVodrazka
Date: Mon, 24 Jun 2024 13:33:18 +0200
Subject: [PATCH 02/20] feat: split governance page into subpages
---
package-lock.json | 604 +++++++++++++-----------------
package.json | 4 +-
src/App.tsx | 2 +-
src/hooks/useGovernanceSubpage.ts | 7 +
src/pages/governance.tsx | 109 +++---
src/redux/actions.ts | 5 +
src/redux/reducers/ui.ts | 16 +
7 files changed, 349 insertions(+), 398 deletions(-)
create mode 100644 src/hooks/useGovernanceSubpage.ts
diff --git a/package-lock.json b/package-lock.json
index 11094a8e..087ecef8 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "carmine-finance-app",
- "version": "0.1.0",
+ "version": "1.2.0",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "carmine-finance-app",
- "version": "0.1.0",
+ "version": "1.2.0",
"dependencies": {
"@avnu/avnu-sdk": "^1.2.4",
"@emotion/react": "^11.10.4",
@@ -33,6 +33,7 @@
},
"devDependencies": {
"@babel/plugin-proposal-private-property-in-object": "*",
+ "@babel/plugin-transform-private-property-in-object": "^7.24.7",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^10.0.6",
@@ -112,81 +113,17 @@
}
},
"node_modules/@babel/code-frame": {
- "version": "7.23.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
- "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
+ "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
"dependencies": {
- "@babel/highlight": "^7.23.4",
- "chalk": "^2.4.2"
+ "@babel/highlight": "^7.24.7",
+ "picocolors": "^1.0.0"
},
"engines": {
"node": ">=6.9.0"
}
},
- "node_modules/@babel/code-frame/node_modules/ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "dependencies": {
- "color-convert": "^1.9.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/code-frame/node_modules/chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "dependencies": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/code-frame/node_modules/color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "dependencies": {
- "color-name": "1.1.3"
- }
- },
- "node_modules/@babel/code-frame/node_modules/color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/@babel/code-frame/node_modules/has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/@babel/code-frame/node_modules/supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "dependencies": {
- "has-flag": "^3.0.0"
- },
- "engines": {
- "node": ">=4"
- }
- },
"node_modules/@babel/compat-data": {
"version": "7.23.5",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz",
@@ -271,13 +208,13 @@
}
},
"node_modules/@babel/generator": {
- "version": "7.23.6",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz",
- "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz",
+ "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==",
"dependencies": {
- "@babel/types": "^7.23.6",
- "@jridgewell/gen-mapping": "^0.3.2",
- "@jridgewell/trace-mapping": "^0.3.17",
+ "@babel/types": "^7.24.7",
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^2.5.1"
},
"engines": {
@@ -285,11 +222,11 @@
}
},
"node_modules/@babel/helper-annotate-as-pure": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz",
- "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz",
+ "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==",
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
@@ -330,18 +267,18 @@
}
},
"node_modules/@babel/helper-create-class-features-plugin": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.9.tgz",
- "integrity": "sha512-B2L9neXTIyPQoXDm+NtovPvG6VOLWnaXu3BIeVDWwdKFgG30oNa6CqVGiJPDWQwIAK49t9gnQI9c6K6RzabiKw==",
- "dependencies": {
- "@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-function-name": "^7.23.0",
- "@babel/helper-member-expression-to-functions": "^7.23.0",
- "@babel/helper-optimise-call-expression": "^7.22.5",
- "@babel/helper-replace-supers": "^7.22.20",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz",
+ "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==",
+ "dependencies": {
+ "@babel/helper-annotate-as-pure": "^7.24.7",
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/helper-member-expression-to-functions": "^7.24.7",
+ "@babel/helper-optimise-call-expression": "^7.24.7",
+ "@babel/helper-replace-supers": "^7.24.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
"semver": "^6.3.1"
},
"engines": {
@@ -399,42 +336,46 @@
}
},
"node_modules/@babel/helper-environment-visitor": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
- "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
+ "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==",
+ "dependencies": {
+ "@babel/types": "^7.24.7"
+ },
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
- "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz",
+ "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==",
"dependencies": {
- "@babel/template": "^7.22.15",
- "@babel/types": "^7.23.0"
+ "@babel/template": "^7.24.7",
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-hoist-variables": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
- "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz",
+ "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==",
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-member-expression-to-functions": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz",
- "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz",
+ "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==",
"dependencies": {
- "@babel/types": "^7.23.0"
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
@@ -470,20 +411,20 @@
}
},
"node_modules/@babel/helper-optimise-call-expression": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz",
- "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz",
+ "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==",
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-plugin-utils": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
- "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz",
+ "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg==",
"engines": {
"node": ">=6.9.0"
}
@@ -505,13 +446,13 @@
}
},
"node_modules/@babel/helper-replace-supers": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz",
- "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz",
+ "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==",
"dependencies": {
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-member-expression-to-functions": "^7.22.15",
- "@babel/helper-optimise-call-expression": "^7.22.5"
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-member-expression-to-functions": "^7.24.7",
+ "@babel/helper-optimise-call-expression": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
@@ -532,39 +473,40 @@
}
},
"node_modules/@babel/helper-skip-transparent-expression-wrappers": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz",
- "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz",
+ "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==",
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-split-export-declaration": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
- "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
+ "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
"dependencies": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
- "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz",
+ "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==",
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
+ "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==",
"engines": {
"node": ">=6.9.0"
}
@@ -604,13 +546,14 @@
}
},
"node_modules/@babel/highlight": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
- "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
+ "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
"dependencies": {
- "@babel/helper-validator-identifier": "^7.22.20",
+ "@babel/helper-validator-identifier": "^7.24.7",
"chalk": "^2.4.2",
- "js-tokens": "^4.0.0"
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
},
"engines": {
"node": ">=6.9.0"
@@ -681,9 +624,9 @@
}
},
"node_modules/@babel/parser": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
- "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz",
+ "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==",
"bin": {
"parser": "bin/babel-parser.js"
},
@@ -1678,13 +1621,13 @@
}
},
"node_modules/@babel/plugin-transform-private-property-in-object": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz",
- "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz",
+ "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==",
"dependencies": {
- "@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-create-class-features-plugin": "^7.22.15",
- "@babel/helper-plugin-utils": "^7.22.5",
+ "@babel/helper-annotate-as-pure": "^7.24.7",
+ "@babel/helper-create-class-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7",
"@babel/plugin-syntax-private-property-in-object": "^7.14.5"
},
"engines": {
@@ -2154,31 +2097,31 @@
}
},
"node_modules/@babel/template": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz",
- "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
+ "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
"dependencies": {
- "@babel/code-frame": "^7.23.5",
- "@babel/parser": "^7.23.9",
- "@babel/types": "^7.23.9"
+ "@babel/code-frame": "^7.24.7",
+ "@babel/parser": "^7.24.7",
+ "@babel/types": "^7.24.7"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz",
- "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==",
- "dependencies": {
- "@babel/code-frame": "^7.23.5",
- "@babel/generator": "^7.23.6",
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-function-name": "^7.23.0",
- "@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.23.9",
- "@babel/types": "^7.23.9",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz",
+ "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==",
+ "dependencies": {
+ "@babel/code-frame": "^7.24.7",
+ "@babel/generator": "^7.24.7",
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/helper-hoist-variables": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
+ "@babel/parser": "^7.24.7",
+ "@babel/types": "^7.24.7",
"debug": "^4.3.1",
"globals": "^11.1.0"
},
@@ -2187,12 +2130,12 @@
}
},
"node_modules/@babel/types": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz",
- "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz",
+ "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==",
"dependencies": {
- "@babel/helper-string-parser": "^7.23.4",
- "@babel/helper-validator-identifier": "^7.22.20",
+ "@babel/helper-string-parser": "^7.24.7",
+ "@babel/helper-validator-identifier": "^7.24.7",
"to-fast-properties": "^2.0.0"
},
"engines": {
@@ -3215,13 +3158,13 @@
}
},
"node_modules/@jridgewell/gen-mapping": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
- "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+ "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"dependencies": {
- "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
+ "@jridgewell/trace-mapping": "^0.3.24"
},
"engines": {
"node": ">=6.0.0"
@@ -3236,9 +3179,9 @@
}
},
"node_modules/@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==",
"engines": {
"node": ">=6.0.0"
}
@@ -3258,9 +3201,9 @@
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"node_modules/@jridgewell/trace-mapping": {
- "version": "0.3.22",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz",
- "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==",
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"dependencies": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
@@ -25075,63 +25018,12 @@
"requires": {}
},
"@babel/code-frame": {
- "version": "7.23.5",
- "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz",
- "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz",
+ "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==",
"requires": {
- "@babel/highlight": "^7.23.4",
- "chalk": "^2.4.2"
- },
- "dependencies": {
- "ansi-styles": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
- "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
- "requires": {
- "color-convert": "^1.9.0"
- }
- },
- "chalk": {
- "version": "2.4.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
- "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
- "requires": {
- "ansi-styles": "^3.2.1",
- "escape-string-regexp": "^1.0.5",
- "supports-color": "^5.3.0"
- }
- },
- "color-convert": {
- "version": "1.9.3",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
- "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
- "requires": {
- "color-name": "1.1.3"
- }
- },
- "color-name": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
- "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw=="
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg=="
- },
- "has-flag": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
- "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw=="
- },
- "supports-color": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
- "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
- "requires": {
- "has-flag": "^3.0.0"
- }
- }
+ "@babel/highlight": "^7.24.7",
+ "picocolors": "^1.0.0"
}
},
"@babel/compat-data": {
@@ -25196,22 +25088,22 @@
}
},
"@babel/generator": {
- "version": "7.23.6",
- "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz",
- "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz",
+ "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==",
"requires": {
- "@babel/types": "^7.23.6",
- "@jridgewell/gen-mapping": "^0.3.2",
- "@jridgewell/trace-mapping": "^0.3.17",
+ "@babel/types": "^7.24.7",
+ "@jridgewell/gen-mapping": "^0.3.5",
+ "@jridgewell/trace-mapping": "^0.3.25",
"jsesc": "^2.5.1"
}
},
"@babel/helper-annotate-as-pure": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz",
- "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.24.7.tgz",
+ "integrity": "sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==",
"requires": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.7"
}
},
"@babel/helper-builder-binary-assignment-operator-visitor": {
@@ -25242,18 +25134,18 @@
}
},
"@babel/helper-create-class-features-plugin": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.23.9.tgz",
- "integrity": "sha512-B2L9neXTIyPQoXDm+NtovPvG6VOLWnaXu3BIeVDWwdKFgG30oNa6CqVGiJPDWQwIAK49t9gnQI9c6K6RzabiKw==",
- "requires": {
- "@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-function-name": "^7.23.0",
- "@babel/helper-member-expression-to-functions": "^7.23.0",
- "@babel/helper-optimise-call-expression": "^7.22.5",
- "@babel/helper-replace-supers": "^7.22.20",
- "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.7.tgz",
+ "integrity": "sha512-kTkaDl7c9vO80zeX1rJxnuRpEsD5tA81yh11X1gQo+PhSti3JS+7qeZo9U4RHobKRiFPKaGK3svUAeb8D0Q7eg==",
+ "requires": {
+ "@babel/helper-annotate-as-pure": "^7.24.7",
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/helper-member-expression-to-functions": "^7.24.7",
+ "@babel/helper-optimise-call-expression": "^7.24.7",
+ "@babel/helper-replace-supers": "^7.24.7",
+ "@babel/helper-skip-transparent-expression-wrappers": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
"semver": "^6.3.1"
},
"dependencies": {
@@ -25294,33 +25186,37 @@
}
},
"@babel/helper-environment-visitor": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
- "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA=="
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz",
+ "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==",
+ "requires": {
+ "@babel/types": "^7.24.7"
+ }
},
"@babel/helper-function-name": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
- "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz",
+ "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==",
"requires": {
- "@babel/template": "^7.22.15",
- "@babel/types": "^7.23.0"
+ "@babel/template": "^7.24.7",
+ "@babel/types": "^7.24.7"
}
},
"@babel/helper-hoist-variables": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
- "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz",
+ "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==",
"requires": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.7"
}
},
"@babel/helper-member-expression-to-functions": {
- "version": "7.23.0",
- "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz",
- "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.24.7.tgz",
+ "integrity": "sha512-LGeMaf5JN4hAT471eJdBs/GK1DoYIJ5GCtZN/EsL6KUiiDZOvO/eKE11AMZJa2zP4zk4qe9V2O/hxAmkRc8p6w==",
"requires": {
- "@babel/types": "^7.23.0"
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
}
},
"@babel/helper-module-imports": {
@@ -25344,17 +25240,17 @@
}
},
"@babel/helper-optimise-call-expression": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz",
- "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.24.7.tgz",
+ "integrity": "sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==",
"requires": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.7"
}
},
"@babel/helper-plugin-utils": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.22.5.tgz",
- "integrity": "sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg=="
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.7.tgz",
+ "integrity": "sha512-Rq76wjt7yz9AAc1KnlRKNAi/dMSVWgDRx43FHoJEbcYU6xOWaE2dVPwcdTukJrjxS65GITyfbvEYHvkirZ6uEg=="
},
"@babel/helper-remap-async-to-generator": {
"version": "7.22.20",
@@ -25367,13 +25263,13 @@
}
},
"@babel/helper-replace-supers": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.22.20.tgz",
- "integrity": "sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.7.tgz",
+ "integrity": "sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==",
"requires": {
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-member-expression-to-functions": "^7.22.15",
- "@babel/helper-optimise-call-expression": "^7.22.5"
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-member-expression-to-functions": "^7.24.7",
+ "@babel/helper-optimise-call-expression": "^7.24.7"
}
},
"@babel/helper-simple-access": {
@@ -25385,30 +25281,31 @@
}
},
"@babel/helper-skip-transparent-expression-wrappers": {
- "version": "7.22.5",
- "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz",
- "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.24.7.tgz",
+ "integrity": "sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==",
"requires": {
- "@babel/types": "^7.22.5"
+ "@babel/traverse": "^7.24.7",
+ "@babel/types": "^7.24.7"
}
},
"@babel/helper-split-export-declaration": {
- "version": "7.22.6",
- "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
- "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz",
+ "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==",
"requires": {
- "@babel/types": "^7.22.5"
+ "@babel/types": "^7.24.7"
}
},
"@babel/helper-string-parser": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz",
- "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ=="
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz",
+ "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg=="
},
"@babel/helper-validator-identifier": {
- "version": "7.22.20",
- "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
- "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A=="
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz",
+ "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w=="
},
"@babel/helper-validator-option": {
"version": "7.23.5",
@@ -25436,13 +25333,14 @@
}
},
"@babel/highlight": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz",
- "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz",
+ "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==",
"requires": {
- "@babel/helper-validator-identifier": "^7.22.20",
+ "@babel/helper-validator-identifier": "^7.24.7",
"chalk": "^2.4.2",
- "js-tokens": "^4.0.0"
+ "js-tokens": "^4.0.0",
+ "picocolors": "^1.0.0"
},
"dependencies": {
"ansi-styles": {
@@ -25497,9 +25395,9 @@
}
},
"@babel/parser": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.9.tgz",
- "integrity": "sha512-9tcKgqKbs3xGJ+NtKF2ndOBBLVwPjl1SHxPQkd36r3Dlirw3xWUeGaTbqr7uGZcTaxkVNwc+03SVP7aCdWrTlA=="
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz",
+ "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw=="
},
"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": {
"version": "7.23.3",
@@ -26109,13 +26007,13 @@
}
},
"@babel/plugin-transform-private-property-in-object": {
- "version": "7.23.4",
- "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.23.4.tgz",
- "integrity": "sha512-9G3K1YqTq3F4Vt88Djx1UZ79PDyj+yKRnUy7cZGSMe+a7jkwD259uKKuUzQlPkGam7R+8RJwh5z4xO27fA1o2A==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.7.tgz",
+ "integrity": "sha512-9z76mxwnwFxMyxZWEgdgECQglF2Q7cFLm0kMf8pGwt+GSJsY0cONKj/UuO4bOH0w/uAel3ekS4ra5CEAyJRmDA==",
"requires": {
- "@babel/helper-annotate-as-pure": "^7.22.5",
- "@babel/helper-create-class-features-plugin": "^7.22.15",
- "@babel/helper-plugin-utils": "^7.22.5",
+ "@babel/helper-annotate-as-pure": "^7.24.7",
+ "@babel/helper-create-class-features-plugin": "^7.24.7",
+ "@babel/helper-plugin-utils": "^7.24.7",
"@babel/plugin-syntax-private-property-in-object": "^7.14.5"
}
},
@@ -26439,39 +26337,39 @@
}
},
"@babel/template": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.23.9.tgz",
- "integrity": "sha512-+xrD2BWLpvHKNmX2QbpdpsBaWnRxahMwJjO+KZk2JOElj5nSmKezyS1B4u+QbHMTX69t4ukm6hh9lsYQ7GHCKA==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz",
+ "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==",
"requires": {
- "@babel/code-frame": "^7.23.5",
- "@babel/parser": "^7.23.9",
- "@babel/types": "^7.23.9"
+ "@babel/code-frame": "^7.24.7",
+ "@babel/parser": "^7.24.7",
+ "@babel/types": "^7.24.7"
}
},
"@babel/traverse": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.9.tgz",
- "integrity": "sha512-I/4UJ9vs90OkBtY6iiiTORVMyIhJ4kAVmsKo9KFc8UOxMeUfi2hvtIBsET5u9GizXE6/GFSuKCTNfgCswuEjRg==",
- "requires": {
- "@babel/code-frame": "^7.23.5",
- "@babel/generator": "^7.23.6",
- "@babel/helper-environment-visitor": "^7.22.20",
- "@babel/helper-function-name": "^7.23.0",
- "@babel/helper-hoist-variables": "^7.22.5",
- "@babel/helper-split-export-declaration": "^7.22.6",
- "@babel/parser": "^7.23.9",
- "@babel/types": "^7.23.9",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz",
+ "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==",
+ "requires": {
+ "@babel/code-frame": "^7.24.7",
+ "@babel/generator": "^7.24.7",
+ "@babel/helper-environment-visitor": "^7.24.7",
+ "@babel/helper-function-name": "^7.24.7",
+ "@babel/helper-hoist-variables": "^7.24.7",
+ "@babel/helper-split-export-declaration": "^7.24.7",
+ "@babel/parser": "^7.24.7",
+ "@babel/types": "^7.24.7",
"debug": "^4.3.1",
"globals": "^11.1.0"
}
},
"@babel/types": {
- "version": "7.23.9",
- "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.9.tgz",
- "integrity": "sha512-dQjSq/7HaSjRM43FFGnv5keM2HsxpmyV1PfaSVm0nzzjwwTmjOe6J4bC8e3+pTEIgHaHj+1ZlLThRJ2auc/w1Q==",
+ "version": "7.24.7",
+ "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz",
+ "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==",
"requires": {
- "@babel/helper-string-parser": "^7.23.4",
- "@babel/helper-validator-identifier": "^7.22.20",
+ "@babel/helper-string-parser": "^7.24.7",
+ "@babel/helper-validator-identifier": "^7.24.7",
"to-fast-properties": "^2.0.0"
}
},
@@ -27169,13 +27067,13 @@
}
},
"@jridgewell/gen-mapping": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
- "integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
+ "version": "0.3.5",
+ "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz",
+ "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==",
"requires": {
- "@jridgewell/set-array": "^1.0.1",
+ "@jridgewell/set-array": "^1.2.1",
"@jridgewell/sourcemap-codec": "^1.4.10",
- "@jridgewell/trace-mapping": "^0.3.9"
+ "@jridgewell/trace-mapping": "^0.3.24"
}
},
"@jridgewell/resolve-uri": {
@@ -27184,9 +27082,9 @@
"integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA=="
},
"@jridgewell/set-array": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
- "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw=="
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz",
+ "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A=="
},
"@jridgewell/source-map": {
"version": "0.3.5",
@@ -27203,9 +27101,9 @@
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
},
"@jridgewell/trace-mapping": {
- "version": "0.3.22",
- "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz",
- "integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==",
+ "version": "0.3.25",
+ "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz",
+ "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==",
"requires": {
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
diff --git a/package.json b/package.json
index 521cad04..a0cab802 100644
--- a/package.json
+++ b/package.json
@@ -51,7 +51,7 @@
]
},
"devDependencies": {
- "@babel/plugin-proposal-private-property-in-object": "*",
+ "@babel/plugin-transform-private-property-in-object": "^7.24.7",
"@semantic-release/changelog": "^6.0.3",
"@semantic-release/git": "^10.0.1",
"@semantic-release/github": "^10.0.6",
@@ -74,4 +74,4 @@
"typescript": "^4.8.4",
"web-vitals": "^2.1.4"
}
-}
+}
\ No newline at end of file
diff --git a/src/App.tsx b/src/App.tsx
index 4122e876..0114908a 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -67,7 +67,7 @@ const App = () => {
} />
} />
} />
- } />
+ } />
} />
} />
} />
diff --git a/src/hooks/useGovernanceSubpage.ts b/src/hooks/useGovernanceSubpage.ts
new file mode 100644
index 00000000..4906edf5
--- /dev/null
+++ b/src/hooks/useGovernanceSubpage.ts
@@ -0,0 +1,7 @@
+import { useSelector } from "react-redux";
+
+import { GovernanceSubpage } from "../redux/reducers/ui";
+import { RootState } from "../redux/store";
+
+export const useGovernanceSubpage = (): GovernanceSubpage =>
+ useSelector((s: RootState) => s.ui.governanceSubpage);
diff --git a/src/pages/governance.tsx b/src/pages/governance.tsx
index 7bf5b1f8..11a6934c 100644
--- a/src/pages/governance.tsx
+++ b/src/pages/governance.tsx
@@ -1,40 +1,45 @@
-import { Box, Typography } from "@mui/material";
import { Helmet } from "react-helmet";
import { Layout } from "../components/Layout";
import { Proposals } from "../components/Proposal";
-import { isMainnet } from "../constants/amm";
import { Vest } from "../components/Vesting";
+import { useGovernanceSubpage } from "../hooks/useGovernanceSubpage";
+import { GovernanceSubpage } from "../redux/reducers/ui";
+import { useNavigate } from "react-router-dom";
+import buttonStyles from "../style/button.module.css";
+import { setGovernanceSubpage } from "../redux/actions";
+import { Airdrop } from "../components/Airdrop/Airdrop";
-type Props = {
- message: string;
- data?: string[];
+const VotingSubpage = () => {
+ return (
+
+
Proposals
+
Vote on AMM defining proposals
+
+
+ );
};
-const Governance = () => {
- const SwitchNetwork = ({ message, data }: Props) => (
-
-
- {message}
- {/* */}
- {/* {account && } */}
-
-
+const StakingSubpage = () => {
+ return (
+
+
CARM Staking
+
+ Stake your CARM
+
+
+
);
+};
+
+const Governance = () => {
+ const subpage = useGovernanceSubpage();
+ const navigate = useNavigate();
+
+ const handleNavigateClick = (subpage: GovernanceSubpage) => {
+ setGovernanceSubpage(subpage);
+ navigate(`/governance/${subpage}`);
+ };
return (
@@ -45,20 +50,40 @@ const Governance = () => {
content="Vote on proposals and take part in governing Carmine Options AMM"
/>
- {isMainnet ? (
-
-
CARM Staking
-
- Stake your CARM
-
-
-
Proposals
-
Vote on AMM defining proposals
-
-
- ) : (
-
- )}
+
+
+
+
+ {subpage === GovernanceSubpage.Voting && }
+ {subpage === GovernanceSubpage.Staking && }
+ {subpage === GovernanceSubpage.AirDrop && }
);
};
diff --git a/src/redux/actions.ts b/src/redux/actions.ts
index f6934113..c49449f0 100644
--- a/src/redux/actions.ts
+++ b/src/redux/actions.ts
@@ -3,10 +3,12 @@ import { updateNetworkState } from "./reducers/network";
import {
addReferredPairState,
DialogContentElem,
+ GovernanceSubpage,
PortfolioParamType,
ReferralSent,
setBuyInsuranceModalState,
setCloseOptionState,
+ setGovernanceSubpageState,
setParamState,
setToastState,
setTransferDataModalState,
@@ -125,3 +127,6 @@ export const markTxAsFailed = (hash: string) =>
export const addReferredPair = (pair: ReferralSent) =>
store.dispatch(addReferredPairState(pair));
+
+export const setGovernanceSubpage = (subpage: GovernanceSubpage) =>
+ store.dispatch(setGovernanceSubpageState(subpage));
diff --git a/src/redux/reducers/ui.ts b/src/redux/reducers/ui.ts
index 4a13a301..8b98c141 100644
--- a/src/redux/reducers/ui.ts
+++ b/src/redux/reducers/ui.ts
@@ -30,6 +30,12 @@ export enum PortfolioParamType {
Referral = "referral",
}
+export enum GovernanceSubpage {
+ AirDrop = "airdrop",
+ Voting = "voting",
+ Staking = "staking",
+}
+
export type ToastState = {
message: string;
open: boolean;
@@ -50,6 +56,7 @@ export interface UiState {
transferData?: TransferData;
transferDialogShown: boolean;
portfolioParam?: PortfolioParamType;
+ governanceSubpage: GovernanceSubpage;
referralsSent: ReferralSent[];
}
@@ -61,6 +68,7 @@ export const ui = createSlice({
toastState: { message: "", type: ToastType.Info, open: false },
transferDialogShown: false,
portfolioParam: PortfolioParamType.Position,
+ governanceSubpage: GovernanceSubpage.Voting,
referralsSent: [],
} as UiState,
reducers: {
@@ -101,6 +109,13 @@ export const ui = createSlice({
state.portfolioParam = action.payload;
return state;
},
+ setGovernanceSubpageState: (
+ state,
+ action: { payload: GovernanceSubpage }
+ ) => {
+ state.governanceSubpage = action.payload;
+ return state;
+ },
addReferredPairState: (state, action: { payload: ReferralSent }) => {
state.referralsSent = [...state.referralsSent, action.payload];
return state;
@@ -116,5 +131,6 @@ export const {
setTransferDataModalState,
setTransferDialogShown,
setParamState,
+ setGovernanceSubpageState,
addReferredPairState,
} = ui.actions;
From 582a590694df27a169ec21f9d7545c0899e2b7d8 Mon Sep 17 00:00:00 2001
From: DaveVodrazka
Date: Thu, 27 Jun 2024 11:31:21 +0200
Subject: [PATCH 03/20] feat: new airdrop and staking
---
config-mainnet.json | 2 +
config-testnet.json | 4 +-
src/abi/governance_abi.json | 819 ++++++++++++++++--
src/calls/balanceOf.ts | 16 +-
src/calls/carmineStake.ts | 172 ++++
src/classes/CarmineStake.ts | 84 ++
src/components/Airdrop/Airdrop.tsx | 140 +--
src/components/Airdrop/AirdropModal.tsx | 270 ++++++
src/components/Airdrop/airdrop.module.css | 46 +
src/components/Airdrop/getProof.ts | 50 +-
src/components/CarmineStaking/StakeCRM.tsx | 184 ++++
src/components/CarmineStaking/Stakes.tsx | 154 ++++
src/components/CarmineStaking/Staking.tsx | 65 ++
.../CarmineStaking/StakingModal.tsx | 213 +++++
src/components/CarmineStaking/calls.ts | 53 ++
src/components/CarmineStaking/index.ts | 3 +
.../CarmineStaking/modal.module.css | 28 +
src/components/CarmineStaking/vest.module.css | 20 +
src/components/Slip/Slip.tsx | 20 +-
src/components/Vesting/Vest.tsx | 76 --
src/components/Vesting/calls.ts | 7 -
src/components/Vesting/index.ts | 3 -
src/components/Vesting/vest.module.css | 5 -
src/constants/amm.ts | 4 +
src/constants/config.json | 2 +
src/constants/starknet.ts | 12 +
src/network/provider.ts | 1 +
src/pages/governance.tsx | 24 +-
src/queries/client.ts | 2 +
src/queries/keys.ts | 2 +
src/redux/reducers/transactions.ts | 2 +
src/style/button.module.css | 5 +
src/style/input.module.css | 2 +-
src/types/governance.ts | 7 +
src/types/network.ts | 9 +
35 files changed, 2226 insertions(+), 280 deletions(-)
create mode 100644 src/calls/carmineStake.ts
create mode 100644 src/classes/CarmineStake.ts
create mode 100644 src/components/Airdrop/AirdropModal.tsx
create mode 100644 src/components/CarmineStaking/StakeCRM.tsx
create mode 100644 src/components/CarmineStaking/Stakes.tsx
create mode 100644 src/components/CarmineStaking/Staking.tsx
create mode 100644 src/components/CarmineStaking/StakingModal.tsx
create mode 100644 src/components/CarmineStaking/calls.ts
create mode 100644 src/components/CarmineStaking/index.ts
create mode 100644 src/components/CarmineStaking/modal.module.css
create mode 100644 src/components/CarmineStaking/vest.module.css
delete mode 100644 src/components/Vesting/Vest.tsx
delete mode 100644 src/components/Vesting/calls.ts
delete mode 100644 src/components/Vesting/index.ts
delete mode 100644 src/components/Vesting/vest.module.css
create mode 100644 src/types/governance.ts
diff --git a/config-mainnet.json b/config-mainnet.json
index 63f1567d..1fd8caa0 100644
--- a/config-mainnet.json
+++ b/config-mainnet.json
@@ -7,6 +7,8 @@
"USDC_ADDRESS": "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8",
"BTC_ADDRESS": "0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac",
"STRK_ADDRESS": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
+ "VE_CRM_ADDRESS": "0x3c0286e9e428a130ae7fbbe911b794e8a829c367dd788e7cfe3efb0367548fa",
+ "CRM_ADDRESS": "0x51c4b1fe3bf6774b87ad0b15ef5d1472759076e42944fff9b9f641ff13e5bbe",
"ETH_USDC_CALL_ADDRESS": "0x70cad6be2c3fc48c745e4a4b70ef578d9c79b46ffac4cd93ec7b61f951c7c5c",
"ETH_USDC_PUT_ADDRESS": "0x466e3a6731571cf5d74c5b0d9c508bfb71438de10f9a13269177b01d6f07159",
"BTC_USDC_CALL_ADDRESS": "0x35db72a814c9b30301f646a8fa8c192ff63a0dc82beb390a36e6e9eba55b6db",
diff --git a/config-testnet.json b/config-testnet.json
index 27ea8f5f..65979b6a 100644
--- a/config-testnet.json
+++ b/config-testnet.json
@@ -2,11 +2,13 @@
"NETWORK": "testnet",
"API_URL": "https://api.carmine.finance",
"AMM_ADDRESS": "0x07587280e108db0681eb60190ed1f5bd737965177f6c13551ab2e50d6644d382",
- "GOVERNANCE_ADDRESS": "TODO",
+ "GOVERNANCE_ADDRESS": "0x02c027aad2668aa66d232d846c190785ade993b032f9ad44893739b365b89d34",
"ETH_ADDRESS": "0x49d36570d4e46f48e99674bd3fcc84644ddd6b96f7c741b1562b82f9e004dc7",
"USDC_ADDRESS": "0x07b5be4ebf7c50f67d54d328c45ee21b06de8e39240c7943b25ab811c07c43e4",
"BTC_ADDRESS": "0x00c6164da852d230360333d6ade3551ee3e48124c815704f51fa7f12d8287dcc",
"STRK_ADDRESS": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
+ "VE_CRM_ADDRESS": "0x4a6bd0934f92e8419280e3b7d83db9a1ed15c25991ee91713042dddebe72b7e",
+ "CRM_ADDRESS": "0x5e5bf796ce003158104836ce0eb92ba4387676cc43ba9bfa540cdabe66c2c7e",
"ETH_USDC_CALL_ADDRESS": "0x201f9513450a32a1f3803f289ee7d104735cd1f933712fffc1cdae98ad6c008",
"ETH_USDC_PUT_ADDRESS": "0x3271dbd7dc85550648cd561595fae76393490a8650b9225e9b4392e09b20c7c",
"BTC_USDC_CALL_ADDRESS": "0x6fbe70f97f93f9b42707b7cadabba472eb810af5fe1f06da04583b1724a8c2b",
diff --git a/src/abi/governance_abi.json b/src/abi/governance_abi.json
index e419cbea..d7b6fdac 100644
--- a/src/abi/governance_abi.json
+++ b/src/abi/governance_abi.json
@@ -1,132 +1,787 @@
[
{
+ "name": "Governance",
+ "type": "impl",
+ "interface_name": "konoha::contract::IGovernance"
+ },
+ {
+ "name": "konoha::contract::IGovernance",
+ "type": "interface",
+ "items": [
+ {
+ "name": "get_governance_token_address",
+ "type": "function",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ],
+ "state_mutability": "view"
+ }
+ ]
+ },
+ {
+ "name": "CarmineGovernance",
+ "type": "impl",
+ "interface_name": "amm_governance::contract::ICarmineGovernance"
+ },
+ {
+ "name": "amm_governance::contract::ICarmineGovernance",
+ "type": "interface",
+ "items": [
+ {
+ "name": "get_amm_address",
+ "type": "function",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ],
+ "state_mutability": "view"
+ }
+ ]
+ },
+ {
+ "name": "Migrate",
+ "type": "impl",
+ "interface_name": "amm_governance::contract::IMigrate"
+ },
+ {
+ "name": "amm_governance::contract::IMigrate",
+ "type": "interface",
+ "items": [
+ {
+ "name": "add_custom_proposals",
+ "type": "function",
+ "inputs": [],
+ "outputs": [],
+ "state_mutability": "external"
+ }
+ ]
+ },
+ {
+ "name": "Airdrop",
+ "type": "impl",
+ "interface_name": "konoha::airdrop::IAirdrop"
+ },
+ {
+ "name": "konoha::airdrop::IAirdrop",
+ "type": "interface",
+ "items": [
+ {
+ "name": "claim",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "claimee",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "name": "amount",
+ "type": "core::integer::u128"
+ },
+ {
+ "name": "proof",
+ "type": "core::array::Array::"
+ }
+ ],
+ "outputs": [],
+ "state_mutability": "external"
+ }
+ ]
+ },
+ {
+ "name": "Proposals",
+ "type": "impl",
+ "interface_name": "amm_governance::proposals::IProposals"
+ },
+ {
+ "name": "konoha::types::PropDetails",
"type": "struct",
- "name": "governance::types::PropDetails",
"members": [
- { "name": "impl_hash", "type": "core::felt252" },
- { "name": "to_upgrade", "type": "core::felt252" }
+ {
+ "name": "payload",
+ "type": "core::felt252"
+ },
+ {
+ "name": "to_upgrade",
+ "type": "core::felt252"
+ }
]
},
{
- "type": "function",
- "name": "get_proposal_details",
- "inputs": [{ "name": "prop_id", "type": "core::felt252" }],
- "outputs": [{ "type": "governance::types::PropDetails" }],
- "state_mutability": "view"
+ "name": "core::array::Span::",
+ "type": "struct",
+ "members": [
+ {
+ "name": "snapshot",
+ "type": "@core::array::Array::"
+ }
+ ]
},
{
- "type": "function",
- "name": "get_vote_counts",
- "inputs": [{ "name": "prop_id", "type": "core::felt252" }],
- "outputs": [{ "type": "(core::integer::u128, core::integer::u128)" }],
- "state_mutability": "view"
+ "name": "core::bool",
+ "type": "enum",
+ "variants": [
+ {
+ "name": "False",
+ "type": "()"
+ },
+ {
+ "name": "True",
+ "type": "()"
+ }
+ ]
},
{
- "type": "function",
- "name": "submit_proposal",
- "inputs": [
- { "name": "impl_hash", "type": "core::felt252" },
- { "name": "to_upgrade", "type": "core::felt252" }
- ],
- "outputs": [{ "type": "core::felt252" }],
- "state_mutability": "external"
+ "name": "konoha::types::CustomProposalConfig",
+ "type": "struct",
+ "members": [
+ {
+ "name": "target",
+ "type": "core::felt252"
+ },
+ {
+ "name": "selector",
+ "type": "core::felt252"
+ },
+ {
+ "name": "library_call",
+ "type": "core::bool"
+ }
+ ]
},
{
- "type": "function",
- "name": "vote",
- "inputs": [
- { "name": "prop_id", "type": "core::felt252" },
- { "name": "opinion", "type": "core::felt252" }
- ],
- "outputs": [],
- "state_mutability": "external"
+ "name": "amm_governance::proposals::IProposals",
+ "type": "interface",
+ "items": [
+ {
+ "name": "vote",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "prop_id",
+ "type": "core::felt252"
+ },
+ {
+ "name": "opinion",
+ "type": "core::felt252"
+ }
+ ],
+ "outputs": [],
+ "state_mutability": "external"
+ },
+ {
+ "name": "get_proposal_details",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "prop_id",
+ "type": "core::felt252"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "konoha::types::PropDetails"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "name": "get_vote_counts",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "prop_id",
+ "type": "core::felt252"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "(core::integer::u128, core::integer::u128)"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "name": "submit_proposal",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "payload",
+ "type": "core::felt252"
+ },
+ {
+ "name": "to_upgrade",
+ "type": "core::integer::u64"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "core::felt252"
+ }
+ ],
+ "state_mutability": "external"
+ },
+ {
+ "name": "get_proposal_status",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "prop_id",
+ "type": "core::felt252"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "core::felt252"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "name": "get_live_proposals",
+ "type": "function",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "core::array::Array::"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "name": "get_user_voted",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "user_address",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "name": "prop_id",
+ "type": "core::felt252"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "core::felt252"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "name": "submit_custom_proposal",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "custom_proposal_type",
+ "type": "core::integer::u32"
+ },
+ {
+ "name": "calldata",
+ "type": "core::array::Span::"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "core::integer::u32"
+ }
+ ],
+ "state_mutability": "external"
+ },
+ {
+ "name": "get_custom_proposal_type",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "i",
+ "type": "core::integer::u32"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "konoha::types::CustomProposalConfig"
+ }
+ ],
+ "state_mutability": "view"
+ }
+ ]
},
{
- "type": "function",
- "name": "get_proposal_status",
- "inputs": [{ "name": "prop_id", "type": "core::felt252" }],
- "outputs": [{ "type": "core::felt252" }],
- "state_mutability": "view"
+ "name": "Upgrades",
+ "type": "impl",
+ "interface_name": "amm_governance::upgrades::IUpgrades"
},
{
- "type": "function",
- "name": "vote_investor",
- "inputs": [
- { "name": "prop_id", "type": "core::felt252" },
- { "name": "opinion", "type": "core::felt252" }
- ],
- "outputs": [],
- "state_mutability": "external"
+ "name": "amm_governance::upgrades::IUpgrades",
+ "type": "interface",
+ "items": [
+ {
+ "name": "apply_passed_proposal",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "prop_id",
+ "type": "core::felt252"
+ }
+ ],
+ "outputs": [],
+ "state_mutability": "external"
+ }
+ ]
},
{
- "type": "function",
- "name": "get_governance_token_address",
- "inputs": [],
- "outputs": [
- { "type": "core::starknet::contract_address::ContractAddress" }
- ],
- "state_mutability": "view"
+ "name": "Staking",
+ "type": "impl",
+ "interface_name": "amm_governance::staking::IStaking"
},
{
- "type": "function",
- "name": "get_amm_address",
- "inputs": [],
- "outputs": [
- { "type": "core::starknet::contract_address::ContractAddress" }
- ],
- "state_mutability": "view"
+ "name": "amm_governance::staking::staking::Stake",
+ "type": "struct",
+ "members": [
+ {
+ "name": "amount_staked",
+ "type": "core::integer::u128"
+ },
+ {
+ "name": "amount_voting_token",
+ "type": "core::integer::u128"
+ },
+ {
+ "name": "start_date",
+ "type": "core::integer::u64"
+ },
+ {
+ "name": "length",
+ "type": "core::integer::u64"
+ },
+ {
+ "name": "withdrawn",
+ "type": "core::bool"
+ }
+ ]
},
{
- "type": "function",
- "name": "apply_passed_proposal",
- "inputs": [{ "name": "prop_id", "type": "core::felt252" }],
- "outputs": [],
- "state_mutability": "external"
+ "name": "amm_governance::staking::IStaking",
+ "type": "interface",
+ "items": [
+ {
+ "name": "stake",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "length",
+ "type": "core::integer::u64"
+ },
+ {
+ "name": "amount",
+ "type": "core::integer::u128"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "core::integer::u32"
+ }
+ ],
+ "state_mutability": "external"
+ },
+ {
+ "name": "unstake",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "id",
+ "type": "core::integer::u32"
+ }
+ ],
+ "outputs": [],
+ "state_mutability": "external"
+ },
+ {
+ "name": "unstake_airdrop",
+ "type": "function",
+ "inputs": [],
+ "outputs": [],
+ "state_mutability": "external"
+ },
+ {
+ "name": "set_curve_point",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "length",
+ "type": "core::integer::u64"
+ },
+ {
+ "name": "conversion_rate",
+ "type": "core::integer::u16"
+ }
+ ],
+ "outputs": [],
+ "state_mutability": "external"
+ },
+ {
+ "name": "set_floating_token_address",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "address",
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ],
+ "outputs": [],
+ "state_mutability": "external"
+ },
+ {
+ "name": "initialize_floating_token_address",
+ "type": "function",
+ "inputs": [],
+ "outputs": [],
+ "state_mutability": "external"
+ },
+ {
+ "name": "get_floating_token_address",
+ "type": "function",
+ "inputs": [],
+ "outputs": [
+ {
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "name": "get_stake",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "address",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "name": "stake_id",
+ "type": "core::integer::u32"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "amm_governance::staking::staking::Stake"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "name": "get_total_voting_power",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "address",
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "core::integer::u128"
+ }
+ ],
+ "state_mutability": "view"
+ },
+ {
+ "name": "get_adjusted_voting_power",
+ "type": "function",
+ "inputs": [
+ {
+ "name": "address",
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ],
+ "outputs": [
+ {
+ "type": "core::integer::u128"
+ }
+ ],
+ "state_mutability": "view"
+ }
+ ]
},
{
- "type": "function",
- "name": "claim",
+ "name": "constructor",
+ "type": "constructor",
"inputs": [
{
+ "name": "voting_token_class",
+ "type": "core::starknet::class_hash::ClassHash"
+ },
+ {
+ "name": "floating_token_class",
+ "type": "core::starknet::class_hash::ClassHash"
+ },
+ {
+ "name": "recipient",
+ "type": "core::starknet::contract_address::ContractAddress"
+ }
+ ]
+ },
+ {
+ "kind": "struct",
+ "name": "konoha::airdrop::airdrop::Claimed",
+ "type": "event",
+ "members": [
+ {
+ "kind": "data",
"name": "address",
"type": "core::starknet::contract_address::ContractAddress"
},
- { "name": "amount", "type": "core::integer::u128" },
- { "name": "proof", "type": "core::array::Array::" }
- ],
- "outputs": [],
- "state_mutability": "external"
+ {
+ "kind": "data",
+ "name": "received",
+ "type": "core::integer::u128"
+ }
+ ]
},
{
+ "kind": "enum",
+ "name": "konoha::airdrop::airdrop::Event",
"type": "event",
- "name": "Proposed",
- "inputs": [
- { "name": "prop_id", "type": "core::felt252" },
- { "name": "impl_hash", "type": "core::felt252" },
- { "name": "to_upgrade", "type": "core::felt252" }
+ "variants": [
+ {
+ "kind": "nested",
+ "name": "Claimed",
+ "type": "konoha::airdrop::airdrop::Claimed"
+ }
]
},
{
+ "kind": "struct",
+ "name": "amm_governance::proposals::proposals::Proposed",
"type": "event",
- "name": "Voted",
- "inputs": [
- { "name": "prop_id", "type": "core::felt252" },
+ "members": [
{
+ "kind": "data",
+ "name": "prop_id",
+ "type": "core::felt252"
+ },
+ {
+ "kind": "data",
+ "name": "payload",
+ "type": "core::felt252"
+ },
+ {
+ "kind": "data",
+ "name": "to_upgrade",
+ "type": "core::integer::u64"
+ }
+ ]
+ },
+ {
+ "kind": "struct",
+ "name": "amm_governance::proposals::proposals::Voted",
+ "type": "event",
+ "members": [
+ {
+ "kind": "data",
+ "name": "prop_id",
+ "type": "core::felt252"
+ },
+ {
+ "kind": "data",
"name": "voter",
"type": "core::starknet::contract_address::ContractAddress"
},
- { "name": "opinion", "type": "core::felt252" }
+ {
+ "kind": "data",
+ "name": "opinion",
+ "type": "core::felt252"
+ }
+ ]
+ },
+ {
+ "kind": "enum",
+ "name": "amm_governance::proposals::proposals::Event",
+ "type": "event",
+ "variants": [
+ {
+ "kind": "nested",
+ "name": "Proposed",
+ "type": "amm_governance::proposals::proposals::Proposed"
+ },
+ {
+ "kind": "nested",
+ "name": "Voted",
+ "type": "amm_governance::proposals::proposals::Voted"
+ }
]
},
{
+ "kind": "struct",
+ "name": "amm_governance::upgrades::upgrades::Upgraded",
"type": "event",
- "name": "Claimed",
- "inputs": [
+ "members": [
{
- "name": "address",
+ "kind": "data",
+ "name": "prop_id",
+ "type": "core::integer::u64"
+ },
+ {
+ "kind": "data",
+ "name": "upgrade_type",
+ "type": "core::integer::u64"
+ }
+ ]
+ },
+ {
+ "kind": "enum",
+ "name": "amm_governance::upgrades::upgrades::Event",
+ "type": "event",
+ "variants": [
+ {
+ "kind": "nested",
+ "name": "Upgraded",
+ "type": "amm_governance::upgrades::upgrades::Upgraded"
+ }
+ ]
+ },
+ {
+ "kind": "struct",
+ "name": "amm_governance::staking::staking::Staked",
+ "type": "event",
+ "members": [
+ {
+ "kind": "data",
+ "name": "user",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "kind": "data",
+ "name": "stake_id",
+ "type": "core::integer::u32"
+ },
+ {
+ "kind": "data",
+ "name": "amount",
+ "type": "core::integer::u128"
+ },
+ {
+ "kind": "data",
+ "name": "amount_voting_token",
+ "type": "core::integer::u128"
+ },
+ {
+ "kind": "data",
+ "name": "start_date",
+ "type": "core::integer::u64"
+ },
+ {
+ "kind": "data",
+ "name": "length",
+ "type": "core::integer::u64"
+ }
+ ]
+ },
+ {
+ "kind": "struct",
+ "name": "amm_governance::staking::staking::Unstaked",
+ "type": "event",
+ "members": [
+ {
+ "kind": "data",
+ "name": "user",
+ "type": "core::starknet::contract_address::ContractAddress"
+ },
+ {
+ "kind": "data",
+ "name": "stake_id",
+ "type": "core::integer::u32"
+ },
+ {
+ "kind": "data",
+ "name": "amount",
+ "type": "core::integer::u128"
+ },
+ {
+ "kind": "data",
+ "name": "amount_voting_token",
+ "type": "core::integer::u128"
+ },
+ {
+ "kind": "data",
+ "name": "start_date",
+ "type": "core::integer::u64"
+ },
+ {
+ "kind": "data",
+ "name": "length",
+ "type": "core::integer::u64"
+ }
+ ]
+ },
+ {
+ "kind": "struct",
+ "name": "amm_governance::staking::staking::UnstakedAirdrop",
+ "type": "event",
+ "members": [
+ {
+ "kind": "data",
+ "name": "user",
"type": "core::starknet::contract_address::ContractAddress"
},
- { "name": "received", "type": "core::integer::u128" }
+ {
+ "kind": "data",
+ "name": "amount",
+ "type": "core::integer::u128"
+ }
+ ]
+ },
+ {
+ "kind": "enum",
+ "name": "amm_governance::staking::staking::Event",
+ "type": "event",
+ "variants": [
+ {
+ "kind": "nested",
+ "name": "Staked",
+ "type": "amm_governance::staking::staking::Staked"
+ },
+ {
+ "kind": "nested",
+ "name": "Unstaked",
+ "type": "amm_governance::staking::staking::Unstaked"
+ },
+ {
+ "kind": "nested",
+ "name": "UnstakedAirdrop",
+ "type": "amm_governance::staking::staking::UnstakedAirdrop"
+ }
+ ]
+ },
+ {
+ "kind": "enum",
+ "name": "amm_governance::contract::Governance::Event",
+ "type": "event",
+ "variants": [
+ {
+ "kind": "nested",
+ "name": "AirdropEvent",
+ "type": "konoha::airdrop::airdrop::Event"
+ },
+ {
+ "kind": "nested",
+ "name": "ProposalsEvent",
+ "type": "amm_governance::proposals::proposals::Event"
+ },
+ {
+ "kind": "nested",
+ "name": "UpgradesEvent",
+ "type": "amm_governance::upgrades::upgrades::Event"
+ },
+ {
+ "kind": "nested",
+ "name": "StakingEvent",
+ "type": "amm_governance::staking::staking::Event"
+ }
]
}
-]
+]
\ No newline at end of file
diff --git a/src/calls/balanceOf.ts b/src/calls/balanceOf.ts
index ac62cf83..3224b051 100644
--- a/src/calls/balanceOf.ts
+++ b/src/calls/balanceOf.ts
@@ -6,11 +6,10 @@ import {
ETH_ADDRESS,
STRK_ADDRESS,
USDC_ADDRESS,
+ VE_CRM_ADDRESS,
} from "../constants/amm";
import { Token, TokenKey } from "../classes/Token";
-
-const CARM_TOKEN_ADDRESS =
- "0x3c0286e9e428a130ae7fbbe911b794e8a829c367dd788e7cfe3efb0367548fa";
+import { provider } from "../network/provider";
export const balanceFromTokenAddress = async (
account: AccountInterface,
@@ -57,7 +56,16 @@ export const balanceOfStrk = async (
export const balanceOfCarmineToken = async (
account: AccountInterface
-): Promise => balanceFromTokenAddress(account, CARM_TOKEN_ADDRESS);
+): Promise => balanceFromTokenAddress(account, VE_CRM_ADDRESS);
+
+export const balanceOf = async (
+ address: string,
+ token: string
+): Promise => {
+ const contract = new Contract(ABI, token, provider);
+ const balance = await contract.balanceOf(address);
+ return balance;
+};
export const getUserBalance = async (
account: AccountInterface
diff --git a/src/calls/carmineStake.ts b/src/calls/carmineStake.ts
new file mode 100644
index 00000000..f2569cad
--- /dev/null
+++ b/src/calls/carmineStake.ts
@@ -0,0 +1,172 @@
+import { AccountInterface } from "starknet";
+import { governanceContract } from "../constants/starknet";
+import { CarmineStakeResult } from "../types/governance";
+
+import GovernanceABI from "../abi/governance_abi.json";
+import { GOVERNANCE_ADDRESS } from "../constants/amm";
+import {
+ addTx,
+ markTxAsDone,
+ markTxAsFailed,
+ showToast,
+} from "../redux/actions";
+import { TransactionAction } from "../redux/reducers/transactions";
+import { afterTransaction } from "../utils/blockchain";
+import { ToastType } from "../redux/reducers/ui";
+import { TransactionState, TxTracking } from "../types/network";
+import { CarmineStake } from "../classes/CarmineStake";
+
+const isEmptyStake = (stake: CarmineStakeResult): boolean => {
+ if (stake.amount_staked === 0n && stake.start_date === 0n) {
+ return true;
+ }
+ return false;
+};
+
+export const getStakes = async (address: string): Promise => {
+ const increment = 5;
+ const stakes = [];
+ let lastId = 0;
+
+ while (true) {
+ const promises = [];
+ for (let i = lastId; i < lastId + increment; i++) {
+ promises.push(governanceContract.get_stake(address, i));
+ }
+ const values = (await Promise.all(promises)) as CarmineStakeResult[];
+ stakes.push(...values.filter((v) => !isEmptyStake(v)));
+ if (values.find((v) => isEmptyStake(v))) {
+ break;
+ }
+ lastId += increment;
+ }
+
+ return stakes.map((s) => new CarmineStake(s));
+};
+
+export const stakeCarmineToken = async (
+ account: AccountInterface,
+ length: bigint,
+ amount: bigint,
+ setState: TxTracking
+) => {
+ setState(TransactionState.Processing);
+ const call = {
+ contractAddress: GOVERNANCE_ADDRESS,
+ entrypoint: "stake",
+ calldata: [length, amount],
+ };
+ const res = await account.execute(call, [GovernanceABI]).catch(() => {
+ showToast("Failed to stake CRM", ToastType.Error);
+ setState(TransactionState.Fail);
+ return undefined;
+ });
+
+ if (!res) {
+ return;
+ }
+
+ const { transaction_hash: hash } = res;
+
+ addTx(hash, `stake-${hash}`, TransactionAction.TradeOpen);
+ afterTransaction(
+ hash,
+ () => {
+ markTxAsDone(hash);
+ showToast("Successfully staked CRM", ToastType.Success);
+ setState(TransactionState.Success);
+ },
+ () => {
+ markTxAsFailed(hash);
+ showToast("Failed to stake CRM", ToastType.Error);
+ setState(TransactionState.Fail);
+ }
+ );
+};
+
+export const claimAndStakeCarmineToken = async (
+ account: AccountInterface,
+ claimData: string[],
+ length: bigint,
+ amount: bigint,
+ setState: TxTracking
+) => {
+ setState(TransactionState.Processing);
+ const [address, claimAmount, ...proof] = claimData;
+ const claimCall = {
+ contractAddress: GOVERNANCE_ADDRESS,
+ entrypoint: "claim",
+ calldata: [address, claimAmount, String(proof.length), ...proof],
+ };
+ const stakeCall = {
+ contractAddress: GOVERNANCE_ADDRESS,
+ entrypoint: "stake",
+ calldata: [length, amount],
+ };
+ const res = await account
+ .execute([claimCall, stakeCall], [GovernanceABI])
+ .catch(() => {
+ showToast("Failed to claim & stake", ToastType.Error);
+ setState(TransactionState.Fail);
+ return undefined;
+ });
+
+ if (!res) {
+ return;
+ }
+
+ const { transaction_hash: hash } = res;
+
+ addTx(hash, `stake-${hash}`, TransactionAction.TradeOpen);
+ afterTransaction(
+ hash,
+ () => {
+ markTxAsDone(hash);
+ showToast("Successfully claimed & staked CRM", ToastType.Success);
+ setState(TransactionState.Success);
+ },
+ () => {
+ markTxAsFailed(hash);
+ showToast("Failed to claim & stake CRM", ToastType.Error);
+ setState(TransactionState.Fail);
+ }
+ );
+};
+
+export const unstakeAirdrop = async (
+ account: AccountInterface,
+ setTxState: TxTracking
+) => {
+ setTxState(TransactionState.Processing);
+ const call = {
+ contractAddress: GOVERNANCE_ADDRESS,
+ entrypoint: "unstake_airdrop",
+ calldata: [],
+ };
+ const res = await account.execute(call, [GovernanceABI]).catch(() => {
+ showToast("Failed to unstake", ToastType.Error);
+ return undefined;
+ });
+
+ if (!res) {
+ setTxState(TransactionState.Fail);
+ return;
+ }
+
+ const { transaction_hash: hash } = res;
+
+ addTx(hash, `unstake-${hash}`, TransactionAction.ClaimAirdrop);
+ afterTransaction(
+ hash,
+ () => {
+ markTxAsDone(hash);
+ showToast("Successfully unstaked CRM", ToastType.Success);
+ setTxState(TransactionState.Success);
+ },
+ () => {
+ markTxAsFailed(hash);
+ showToast("Failed to unstake CRM", ToastType.Error);
+ setTxState(TransactionState.Fail);
+ }
+ );
+};
diff --git a/src/classes/CarmineStake.ts b/src/classes/CarmineStake.ts
new file mode 100644
index 00000000..88db3dea
--- /dev/null
+++ b/src/classes/CarmineStake.ts
@@ -0,0 +1,84 @@
+import { CARMINE_STAKING_MONTH } from "../constants/amm";
+import { CarmineStakeResult } from "../types/governance";
+import { shortInteger } from "../utils/computations";
+
+const formatDate = (ts: number) =>
+ new Intl.DateTimeFormat("default", {
+ hour: "numeric",
+ minute: "numeric",
+ month: "numeric",
+ day: "numeric",
+ year: "numeric",
+ timeZoneName: "short",
+ }).format(ts * 1000);
+
+export class CarmineStake {
+ public amountStaked;
+ public amountVotingToken;
+ public start;
+ public length;
+ public withdrawn;
+ public end;
+
+ constructor({
+ amount_staked,
+ amount_voting_token,
+ start_date,
+ length,
+ withdrawn,
+ }: CarmineStakeResult) {
+ const numStart = Number(start_date);
+ const numLength = Number(length);
+ this.amountStaked = amount_staked;
+ this.amountVotingToken = amount_voting_token;
+ this.start = numStart;
+ this.length = numLength;
+ this.withdrawn = withdrawn;
+ this.end = numStart + numLength;
+ }
+
+ get isActive(): boolean {
+ const now = Date.now() / 1000;
+ return !this.withdrawn && this.end > now;
+ }
+
+ get isExpired(): boolean {
+ const now = Date.now() / 1000;
+ return !this.withdrawn && this.end <= now;
+ }
+
+ get isNotWithdrawn(): boolean {
+ return !this.withdrawn;
+ }
+
+ get startDate(): string {
+ return formatDate(this.start);
+ }
+
+ get endDate(): string {
+ return formatDate(this.end);
+ }
+
+ get period(): string {
+ const months = this.length / CARMINE_STAKING_MONTH;
+
+ if (months === 1) {
+ return "1 month";
+ }
+ if (months === 12) {
+ return "1 year";
+ }
+ if (months > 12) {
+ return months / 12 + "years";
+ }
+ return months + " months";
+ }
+
+ get amountStakedHumanReadable(): number {
+ return shortInteger(this.amountStaked, 18);
+ }
+
+ get amountVotingTokenHumanReadable(): number {
+ return shortInteger(this.amountVotingToken, 18);
+ }
+}
diff --git a/src/components/Airdrop/Airdrop.tsx b/src/components/Airdrop/Airdrop.tsx
index 7c8e85e5..c23b1557 100644
--- a/src/components/Airdrop/Airdrop.tsx
+++ b/src/components/Airdrop/Airdrop.tsx
@@ -1,97 +1,113 @@
-import { ClaimButton } from "./ClaimButton";
-import { useAccount } from "../../hooks/useAccount";
-import { useEffect, useState } from "react";
-import { useNetwork } from "../../hooks/useNetwork";
-import { ProofResult, getProof } from "./getProof";
+import { useState } from "react";
+import { useQuery } from "react-query";
import { AccountInterface } from "starknet";
+
+import { useAccount } from "../../hooks/useAccount";
+import { Eligible, getAirdropDataQuery } from "./getProof";
import { shortInteger } from "../../utils/computations";
-import { NETWORK } from "../../constants/amm";
+import { isMainnet } from "../../constants/amm";
+import { QueryKeys } from "../../queries/keys";
+import { AirdropModal } from "./AirdropModal";
+
import styles from "../../style/table.module.css";
+import buttonStyles from "../../style/button.module.css";
+import airdropStyles from "./airdrop.module.css";
+
+const ClaimAndStake = ({
+ account,
+ data,
+}: {
+ account: AccountInterface;
+ data: Eligible;
+}) => {
+ const [open, setOpen] = useState(false);
+ const amountHumanReadable = shortInteger(data.claimable, 18);
-type Props = {
- account: AccountInterface | undefined;
- message: string;
- data?: string[];
+ return (
+
+
Airdrop
+
+
+ You are eligible to claim {amountHumanReadable} CRM!
+
+
+
+
+
+ );
};
-const AirdropTemplate = ({ account, message, data }: Props) => (
+const AirdropTemplate = ({ message }: { message: string }) => (
Airdrop
-
- {message} {account && }
-
+
{message}
);
-export const Airdrop = () => {
- const account = useAccount();
- const network = useNetwork();
- const [loading, setLoading] = useState(false);
- const [data, setData] = useState();
-
- const isMainnet = NETWORK === "mainnet";
-
- useEffect(() => {
- if (account && isMainnet) {
- setLoading(true);
- getProof(account).then((res) => {
- setData(res);
- setLoading(false);
- });
- }
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, [account, network]);
-
- if (!isMainnet) {
- return (
-
- );
- }
+export const AirdropWithAccount = ({
+ account,
+}: {
+ account: AccountInterface;
+}) => {
+ const { isLoading, isError, data } = useQuery(
+ [QueryKeys.airdropData, account.address],
+ getAirdropDataQuery
+ );
- if (!account) {
+ if (isError) {
return (
-
+
);
}
- if (loading || !data) {
+ if (isLoading || !data) {
return (
-
+
);
}
if (data.eligible) {
- if (data.claimable === "0") {
+ if (data.claimable === 0n) {
const amount = shortInteger(data.claimed, 18);
return (
);
}
- const amount = shortInteger(data.claimable, 18);
- const message = `${amount} Tokens available.`;
+ return ;
+ }
+
+ return (
+
+ );
+};
+
+export const Airdrop = () => {
+ const account = useAccount();
+ if (!account) {
return (
-
+
);
}
- return (
-
- );
+ if (!isMainnet) {
+ return (
+
+ );
+ }
+
+ return ;
};
diff --git a/src/components/Airdrop/AirdropModal.tsx b/src/components/Airdrop/AirdropModal.tsx
new file mode 100644
index 00000000..ffc464a4
--- /dev/null
+++ b/src/components/Airdrop/AirdropModal.tsx
@@ -0,0 +1,270 @@
+import { Dialog } from "@mui/material";
+import { AccountInterface } from "starknet";
+import { Eligible } from "./getProof";
+
+import { shortInteger } from "../../utils/computations";
+import { CARMINE_STAKING_MONTH, GOVERNANCE_ADDRESS } from "../../constants/amm";
+
+import GovernanceABI from "../../abi/governance_abi.json";
+import {
+ addTx,
+ markTxAsDone,
+ markTxAsFailed,
+ showToast,
+} from "../../redux/actions";
+import { afterTransaction } from "../../utils/blockchain";
+import { TransactionAction } from "../../redux/reducers/transactions";
+import { ToastType } from "../../redux/reducers/ui";
+import { useState } from "react";
+import { TransactionState, TxTracking } from "../../types/network";
+import { LoadingAnimation } from "../Loading/Loading";
+
+import styles from "./airdrop.module.css";
+import buttonStyles from "../../style/button.module.css";
+
+export const claim = async (
+ account: AccountInterface,
+ data: string[],
+ setTxState: TxTracking
+) => {
+ setTxState(TransactionState.Processing);
+ const [address, amount, ...proof] = data;
+
+ // calldata structure explained here: https://github.com/CarmineOptions/carmine-api/tree/master/carmine-api-airdrop
+ // in Cairo, to send array you need to insert the length of array before the array items - "String(proof.length)"
+ const calldata = [address, amount, String(proof.length), ...proof];
+ const call = {
+ contractAddress: GOVERNANCE_ADDRESS,
+ entrypoint: "claim",
+ calldata,
+ };
+ const res = await account.execute(call, [GovernanceABI]).catch(() => null);
+
+ if (res?.transaction_hash) {
+ const hash = res.transaction_hash;
+
+ addTx(hash, "airdrop-claim", TransactionAction.ClaimAirdrop);
+ afterTransaction(
+ res.transaction_hash,
+ () => {
+ setTxState(TransactionState.Success);
+ showToast("Successfully claimed airdrop", ToastType.Success);
+ markTxAsDone(hash);
+ },
+ () => {
+ setTxState(TransactionState.Fail);
+ showToast("Failed claiming airdrop", ToastType.Error);
+ markTxAsFailed(hash);
+ }
+ );
+ } else {
+ setTxState(TransactionState.Fail);
+ showToast("Failed claiming airdrop", ToastType.Error);
+ }
+};
+
+export const claimAndStake = async (
+ account: AccountInterface,
+ data: string[],
+ airdropAmount: bigint,
+ length: number,
+ setTxState: TxTracking
+) => {
+ setTxState(TransactionState.Processing);
+ const [address, amount, ...proof] = data;
+
+ // calldata structure explained here: https://github.com/CarmineOptions/carmine-api/tree/master/carmine-api-airdrop
+ // in Cairo, to send array you need to insert the length of array before the array items - "String(proof.length)"
+ const claimCall = {
+ contractAddress: GOVERNANCE_ADDRESS,
+ entrypoint: "claim",
+ calldata: [address, amount, String(proof.length), ...proof],
+ };
+ const unstakeAirdropCall = {
+ contractAddress: GOVERNANCE_ADDRESS,
+ entrypoint: "unstake_airdrop",
+ calldata: [],
+ };
+ const stakeCall = {
+ contractAddress: GOVERNANCE_ADDRESS,
+ entrypoint: "stake",
+ calldata: [length, airdropAmount],
+ };
+
+ const res = await account
+ .execute(
+ [claimCall, unstakeAirdropCall, stakeCall],
+ [GovernanceABI, GovernanceABI, GovernanceABI]
+ )
+ .catch(() => null);
+
+ if (res?.transaction_hash) {
+ const hash = res.transaction_hash;
+
+ addTx(hash, `airdrop-stake-${length}`, TransactionAction.ClaimAirdrop);
+ afterTransaction(
+ res.transaction_hash,
+ () => {
+ setTxState(TransactionState.Success);
+ showToast("Successfully claimed and staked airdrop", ToastType.Success);
+ markTxAsDone(hash);
+ },
+ () => {
+ setTxState(TransactionState.Fail);
+ showToast("Failed claiming airdrop", ToastType.Error);
+ markTxAsFailed(hash);
+ }
+ );
+ } else {
+ setTxState(TransactionState.Fail);
+ showToast("Failed claiming airdrop", ToastType.Error);
+ }
+};
+
+type Props = {
+ account: AccountInterface;
+ data: Eligible;
+ open: boolean;
+ setOpen: (open: boolean) => void;
+};
+
+const stateToClassName = (state: TransactionState) => {
+ if (state === TransactionState.Success) {
+ return buttonStyles.green;
+ }
+ if (state === TransactionState.Fail) {
+ return buttonStyles.fail;
+ }
+ if (state === TransactionState.Processing) {
+ return buttonStyles.disabled;
+ }
+ return buttonStyles.secondary;
+};
+
+export const AirdropModal = ({ account, data, open, setOpen }: Props) => {
+ const [claimState, setClaimState] = useState(TransactionState.Initial);
+ const [monthState, setMonthState] = useState(TransactionState.Initial);
+ const [sixMonthsState, setSixMonthsState] = useState(
+ TransactionState.Initial
+ );
+ const [yearState, setYearState] = useState(TransactionState.Initial);
+
+ const handleClose = () => {
+ setOpen(false);
+ setClaimState(TransactionState.Initial);
+ setMonthState(TransactionState.Initial);
+ setSixMonthsState(TransactionState.Initial);
+ setYearState(TransactionState.Initial);
+ };
+
+ const handleClaim = () => claim(account, data.proof, setClaimState);
+
+ const handle1month = () => {
+ setSixMonthsState(TransactionState.Processing);
+ setYearState(TransactionState.Processing);
+ claimAndStake(
+ account,
+ data.proof,
+ data.claimable,
+ CARMINE_STAKING_MONTH,
+ setMonthState
+ ).then(() => {
+ setSixMonthsState(TransactionState.Initial);
+ setYearState(TransactionState.Initial);
+ });
+ };
+ const handle6months = () => {
+ setMonthState(TransactionState.Processing);
+ setYearState(TransactionState.Processing);
+ claimAndStake(
+ account,
+ data.proof,
+ data.claimable,
+ 6 * CARMINE_STAKING_MONTH,
+ setSixMonthsState
+ ).then(() => {
+ setMonthState(TransactionState.Initial);
+ setYearState(TransactionState.Initial);
+ });
+ };
+ const handleYear = () => {
+ setMonthState(TransactionState.Processing);
+ setSixMonthsState(TransactionState.Processing);
+ claimAndStake(
+ account,
+ data.proof,
+ data.claimable,
+ CARMINE_STAKING_MONTH,
+ setYearState
+ ).then(() => {
+ setMonthState(TransactionState.Initial);
+ setSixMonthsState(TransactionState.Initial);
+ });
+ };
+
+ return (
+
+ );
+};
diff --git a/src/components/Airdrop/airdrop.module.css b/src/components/Airdrop/airdrop.module.css
index a92c7a2b..1d7b5157 100644
--- a/src/components/Airdrop/airdrop.module.css
+++ b/src/components/Airdrop/airdrop.module.css
@@ -5,6 +5,15 @@
padding: 25px 50px;
}
+.claim {
+ border: 1px solid white;
+ display: inline-flex;
+ align-items: center;
+ justify-content: flex-start;
+ gap: 50px;
+ padding: 20px 50px;
+}
+
.active {
padding-left: 7px;
cursor: pointer;
@@ -14,4 +23,41 @@
.inactive {
padding-left: 7px;
color: gray;
+}
+
+.modal {
+ background: black;
+ border: 1px solid white;
+ padding: 30px;
+}
+
+.modal h3 {
+ margin-top: 0;
+}
+
+.buttongroup {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.singlebutton {
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+}
+
+@media (max-width: 800px) {
+ .claim {
+ flex-flow: column;
+ align-items: center;
+ justify-content: center;
+ gap: 50px;
+ padding: 20px 50px;
+ }
+
+ .buttongroup {
+ flex-flow: column;
+ gap: 15px;
+ }
}
\ No newline at end of file
diff --git a/src/components/Airdrop/getProof.ts b/src/components/Airdrop/getProof.ts
index ccfefc55..4067e60d 100644
--- a/src/components/Airdrop/getProof.ts
+++ b/src/components/Airdrop/getProof.ts
@@ -1,14 +1,13 @@
-import { AccountInterface } from "starknet";
-import { coreTeamAddresses } from "../../constants/amm";
-import { balanceOfCarmineToken } from "../../calls/balanceOf";
-import { hexToBN, standardiseAddress } from "../../utils/utils";
+import { hexToBN } from "../../utils/utils";
import { debug } from "../../utils/debugger";
import { apiUrl } from "../../api";
+import { readStorage } from "../CarmineStaking/calls";
+import { QueryFunctionContext } from "react-query";
-type Eligible = {
+export type Eligible = {
eligible: true;
- claimable: string;
- claimed: string;
+ claimable: bigint;
+ claimed: bigint;
proof: string[];
};
@@ -18,37 +17,25 @@ type NotEligible = {
export type ProofResult = Eligible | NotEligible;
-export const getProof = async (
- account: AccountInterface
-): Promise => {
- const merkleTreeRequest = fetch(
- apiUrl(`airdrop?address=${account.address}`)
- ).then((r) => r.json());
- // since CARM token cannot currently be transfered balanceOf is the amount claimed for tokens
- // that are transferable a view function "claimedAmount" need to be added to airdrop SC
- const carmBalanceRequest = balanceOfCarmineToken(account);
+export const getProof = async (address: string): Promise => {
+ const merkleTreeRequest = fetch(apiUrl(`airdrop?address=${address}`)).then(
+ (r) => r.json()
+ );
+
+ const claimedPromise = readStorage(address);
const [merkleTreeResponse, claimed] = await Promise.all([
merkleTreeRequest,
- carmBalanceRequest,
+ claimedPromise,
]);
if (merkleTreeResponse.status !== "success") {
return { eligible: false };
}
- const isCoreTeam = coreTeamAddresses.includes(
- standardiseAddress(account.address)
- );
-
const total = hexToBN(merkleTreeResponse.data[1]);
const diff = total - claimed;
- // account for tiny differences
- const claimable = isCoreTeam
- ? total.toString(10)
- : diff < 100n
- ? "0"
- : diff.toString(10);
+ const claimable = diff < 100n ? 0n : total - claimed;
debug("CARM token claim data:", {
total: total.toString(10),
@@ -60,6 +47,13 @@ export const getProof = async (
eligible: true,
proof: merkleTreeResponse.data, // proof generated by backend
claimable, // how much can be claimed
- claimed: claimed.toString(10), // how much has been claimed
+ claimed: claimed, // how much has been claimed
};
};
+
+export const getAirdropDataQuery = async ({
+ queryKey,
+}: QueryFunctionContext<[string, string]>): Promise => {
+ const address = queryKey[1];
+ return getProof(address);
+};
diff --git a/src/components/CarmineStaking/StakeCRM.tsx b/src/components/CarmineStaking/StakeCRM.tsx
new file mode 100644
index 00000000..e48a9cb8
--- /dev/null
+++ b/src/components/CarmineStaking/StakeCRM.tsx
@@ -0,0 +1,184 @@
+import { AccountInterface } from "starknet";
+import { useState } from "react";
+import { longInteger, shortInteger } from "../../utils/computations";
+import { CARMINE_STAKING_MONTH, GOVERNANCE_ADDRESS } from "../../constants/amm";
+import { TransactionState, TxTracking } from "../../types/network";
+import { stateToClassName } from "./StakingModal";
+import { LoadingAnimation } from "../Loading/Loading";
+import GovernanceABI from "../../abi/governance_abi.json";
+import { TransactionAction } from "../../redux/reducers/transactions";
+import {
+ addTx,
+ markTxAsDone,
+ markTxAsFailed,
+ showToast,
+} from "../../redux/actions";
+import { afterTransaction } from "../../utils/blockchain";
+import { ToastType } from "../../redux/reducers/ui";
+
+import styles from "./vest.module.css";
+import inputStyles from "../../style/input.module.css";
+import { invalidateKey } from "../../queries/client";
+import { QueryKeys } from "../../queries/keys";
+
+type Props = {
+ account: AccountInterface;
+ carmBalance: bigint;
+};
+
+const stake = async (
+ account: AccountInterface,
+ amount: bigint,
+ length: number,
+ setTxState: TxTracking
+) => {
+ setTxState(TransactionState.Processing);
+
+ const stakeCall = {
+ contractAddress: GOVERNANCE_ADDRESS,
+ entrypoint: "stake",
+ calldata: [length, amount],
+ };
+
+ const res = await account
+ .execute(stakeCall, [GovernanceABI])
+ .catch(() => null);
+
+ if (res?.transaction_hash) {
+ const hash = res.transaction_hash;
+
+ addTx(hash, `stake-${length}`, TransactionAction.ClaimAirdrop);
+ afterTransaction(
+ res.transaction_hash,
+ () => {
+ setTxState(TransactionState.Success);
+ showToast("Successfully claimed and staked airdrop", ToastType.Success);
+ markTxAsDone(hash);
+ // success, refetch new CRM balance
+ invalidateKey(QueryKeys.carmineStakes);
+ },
+ () => {
+ setTxState(TransactionState.Fail);
+ showToast("Failed claiming airdrop", ToastType.Error);
+ markTxAsFailed(hash);
+ }
+ );
+ } else {
+ setTxState(TransactionState.Fail);
+ showToast("Failed claiming airdrop", ToastType.Error);
+ }
+};
+
+export const StakeCrm = ({ account, carmBalance }: Props) => {
+ const [inputValue, setInputValue] = useState("");
+
+ const [monthState, setMonthState] = useState(TransactionState.Initial);
+ const [sixMonthsState, setSixMonthsState] = useState(
+ TransactionState.Initial
+ );
+ const [yearState, setYearState] = useState(TransactionState.Initial);
+
+ const numCarmBalance = shortInteger(carmBalance, 18);
+ const amount = longInteger(parseFloat(inputValue), 18);
+
+ const handle1month = () => {
+ setSixMonthsState(TransactionState.Processing);
+ setYearState(TransactionState.Processing);
+ stake(account, amount, CARMINE_STAKING_MONTH, setMonthState).then(() => {
+ setSixMonthsState(TransactionState.Initial);
+ setYearState(TransactionState.Initial);
+ });
+ };
+ const handle6months = () => {
+ setMonthState(TransactionState.Processing);
+ setYearState(TransactionState.Processing);
+ stake(account, amount, 6 * CARMINE_STAKING_MONTH, setSixMonthsState).then(
+ () => {
+ setMonthState(TransactionState.Initial);
+ setYearState(TransactionState.Initial);
+ }
+ );
+ };
+ const handleYear = () => {
+ setMonthState(TransactionState.Processing);
+ setSixMonthsState(TransactionState.Processing);
+ stake(account, amount, 12 * CARMINE_STAKING_MONTH, setYearState).then(
+ () => {
+ setMonthState(TransactionState.Initial);
+ setSixMonthsState(TransactionState.Initial);
+ }
+ );
+ };
+
+ const handleInputChange = (value: string) => {
+ // Allow empty string, valid number, or a single decimal point followed by numbers
+ const numericValue =
+ value === "" || /^\d*\.?\d{0,6}$/.test(value) ? value : inputValue;
+
+ const num = parseFloat(numericValue);
+
+ if (num && num > numCarmBalance) {
+ // cannot set more than holds
+ return;
+ }
+
+ setInputValue(numericValue);
+ };
+
+ const handleAll = () => setInputValue(numCarmBalance.toString(10));
+
+ return (
+
+
+ Stake your CRM for a period
+
+
+
+ handleInputChange(e.target.value)}
+ />
+
+
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/src/components/CarmineStaking/Stakes.tsx b/src/components/CarmineStaking/Stakes.tsx
new file mode 100644
index 00000000..c234cdcc
--- /dev/null
+++ b/src/components/CarmineStaking/Stakes.tsx
@@ -0,0 +1,154 @@
+import {
+ TableContainer,
+ Table,
+ TableHead,
+ TableRow,
+ TableCell,
+ TableBody,
+} from "@mui/material";
+import { useState } from "react";
+import { AccountInterface } from "starknet";
+
+import { CarmineStake } from "../../classes/CarmineStake";
+import { shortInteger } from "../../utils/computations";
+import { StakingModal } from "./StakingModal";
+
+import tableStyles from "../../style/table.module.css";
+import buttonStyles from "../../style/button.module.css";
+
+const Item = ({ stake }: { stake: CarmineStake }) => {
+ return (
+
+ {stake.startDate}
+ {stake.endDate}
+ {stake.period}
+ {stake.amountStakedHumanReadable}
+ {stake.amountVotingTokenHumanReadable}
+
+ );
+};
+
+const InitialVeCarmItem = ({
+ amount,
+ account,
+}: {
+ amount: bigint;
+ account: AccountInterface;
+}) => {
+ const [open, setOpen] = useState(false);
+
+ return (
+
+ --
+ --
+ --
+ {shortInteger(amount, 18)}
+ 0
+
+
+
+
+
+ );
+};
+
+const ExpiredItem = ({ stake }: { stake: CarmineStake }) => {
+ return (
+
+ {stake.startDate}
+ {stake.endDate}
+ {stake.period}
+ {stake.amountStakedHumanReadable}
+ 0
+
+
+
+
+ );
+};
+
+type Props = {
+ stakes: CarmineStake[];
+ veBalance: bigint;
+ account: AccountInterface;
+};
+
+export const Stakes = ({ stakes, veBalance, account }: Props) => {
+ const balanceInStakes = stakes.reduce((acc, cur) => {
+ if (cur.isNotWithdrawn) {
+ return acc + cur.amountVotingToken;
+ }
+ return acc;
+ }, 0n);
+
+ const active = stakes.filter((s) => s.isActive);
+ const expired = stakes.filter((s) => s.isExpired);
+
+ const initialVeCarm = veBalance - balanceInStakes;
+
+ return (
+
+
Expired stakes
+ {expired.length > 0 || initialVeCarm > 0n ? (
+
+
+
+
+ Start
+ End
+ Period
+ Amount
+ Voting power
+
+
+
+
+ {initialVeCarm > 0n && (
+
+ )}
+ {expired.map((stake, i) => (
+
+ ))}
+
+
+
+ ) : (
+
No expired stakes
+ )}
+
+
Active stakes
+ {active.length > 0 ? (
+
+
+
+
+ Start
+ End
+ Period
+ Amount
+ Voting power
+
+
+
+ {active.map((stake, i) => (
+
+ ))}
+
+
+
+ ) : (
+
No active stakes
+ )}
+
+ );
+};
diff --git a/src/components/CarmineStaking/Staking.tsx b/src/components/CarmineStaking/Staking.tsx
new file mode 100644
index 00000000..d2bb1a40
--- /dev/null
+++ b/src/components/CarmineStaking/Staking.tsx
@@ -0,0 +1,65 @@
+import { AccountInterface } from "starknet";
+import { Skeleton } from "@mui/material";
+import { useQuery } from "react-query";
+
+import { useAccount } from "../../hooks/useAccount";
+import { openWalletConnectDialog } from "../ConnectWallet/Button";
+import { shortInteger } from "../../utils/computations";
+import { Stakes } from "./Stakes";
+import { QueryKeys } from "../../queries/keys";
+import { fetchStakingData } from "./calls";
+import { StakeCrm } from "./StakeCRM";
+
+export const StakeWithAccount = ({
+ account,
+}: {
+ account: AccountInterface;
+}) => {
+ const { isLoading, isError, data } = useQuery(
+ [QueryKeys.carmineStakes, account.address],
+ fetchStakingData
+ );
+ if (isLoading || !data) {
+ return ;
+ }
+
+ if (isError) {
+ return Something went wrong, please try again later
;
+ }
+
+ const { veCarmBalance, carmBalance, stakes } = data;
+
+ const humanReadableVeCarmBalance = shortInteger(veCarmBalance, 18);
+ const humanReadableCarmBalance = shortInteger(carmBalance, 18);
+
+ return (
+
+
+ Find out more about CRM staking and veCRM{" "}
+
+ insert some link here
+
+ .
+
+
+ You have {humanReadableCarmBalance} CRM and{" "}
+ {humanReadableVeCarmBalance} veCRM
+
+ {carmBalance >= 0n && (
+
+ )}
+
+
+
+ );
+};
+
+export const CarmineStaking = () => {
+ const account = useAccount();
+
+ if (!account) {
+ return ;
+ }
+
+ return ;
+};
diff --git a/src/components/CarmineStaking/StakingModal.tsx b/src/components/CarmineStaking/StakingModal.tsx
new file mode 100644
index 00000000..ca253c10
--- /dev/null
+++ b/src/components/CarmineStaking/StakingModal.tsx
@@ -0,0 +1,213 @@
+import { Dialog } from "@mui/material";
+import { AccountInterface } from "starknet";
+
+import { shortInteger } from "../../utils/computations";
+import { CARMINE_STAKING_MONTH, GOVERNANCE_ADDRESS } from "../../constants/amm";
+import GovernanceABI from "../../abi/governance_abi.json";
+import {
+ addTx,
+ markTxAsDone,
+ markTxAsFailed,
+ showToast,
+} from "../../redux/actions";
+import { afterTransaction } from "../../utils/blockchain";
+import { TransactionAction } from "../../redux/reducers/transactions";
+import { ToastType } from "../../redux/reducers/ui";
+import { useState } from "react";
+import { TransactionState, TxTracking } from "../../types/network";
+import { LoadingAnimation } from "../Loading/Loading";
+import { unstakeAirdrop } from "../../calls/carmineStake";
+
+import styles from "./modal.module.css";
+import buttonStyles from "../../style/button.module.css";
+
+export const unstakeAndStake = async (
+ account: AccountInterface,
+ amount: bigint,
+ length: number,
+ setTxState: TxTracking
+) => {
+ setTxState(TransactionState.Processing);
+
+ const unstakeCall = {
+ contractAddress: GOVERNANCE_ADDRESS,
+ entrypoint: "unstake_airdrop",
+ calldata: [],
+ };
+ const stakeCall = {
+ contractAddress: GOVERNANCE_ADDRESS,
+ entrypoint: "stake",
+ calldata: [length, amount],
+ };
+
+ const res = await account
+ .execute([unstakeCall, stakeCall], [GovernanceABI, GovernanceABI])
+ .catch(() => null);
+
+ if (res?.transaction_hash) {
+ const hash = res.transaction_hash;
+
+ addTx(hash, `airdrop-stake-${length}`, TransactionAction.ClaimAirdrop);
+ afterTransaction(
+ res.transaction_hash,
+ () => {
+ setTxState(TransactionState.Success);
+ showToast("Successfully claimed and staked airdrop", ToastType.Success);
+ markTxAsDone(hash);
+ },
+ () => {
+ setTxState(TransactionState.Fail);
+ showToast("Failed claiming airdrop", ToastType.Error);
+ markTxAsFailed(hash);
+ }
+ );
+ } else {
+ setTxState(TransactionState.Fail);
+ showToast("Failed claiming airdrop", ToastType.Error);
+ }
+};
+
+type Props = {
+ account: AccountInterface;
+ amount: bigint;
+ open: boolean;
+ setOpen: (open: boolean) => void;
+};
+
+export const stateToClassName = (state: TransactionState) => {
+ if (state === TransactionState.Success) {
+ return buttonStyles.green;
+ }
+ if (state === TransactionState.Fail) {
+ return buttonStyles.fail;
+ }
+ if (state === TransactionState.Processing) {
+ return buttonStyles.disabled;
+ }
+ return buttonStyles.secondary;
+};
+
+export const StakingModal = ({ account, amount, open, setOpen }: Props) => {
+ const [unstakeState, setUnstakeState] = useState(TransactionState.Initial);
+ const [monthState, setMonthState] = useState(TransactionState.Initial);
+ const [sixMonthsState, setSixMonthsState] = useState(
+ TransactionState.Initial
+ );
+ const [yearState, setYearState] = useState(TransactionState.Initial);
+
+ const handleClose = () => {
+ setOpen(false);
+ setUnstakeState(TransactionState.Initial);
+ setMonthState(TransactionState.Initial);
+ setSixMonthsState(TransactionState.Initial);
+ setYearState(TransactionState.Initial);
+ };
+
+ const handleUnstake = () => unstakeAirdrop(account, setUnstakeState);
+
+ const handle1month = () => {
+ setSixMonthsState(TransactionState.Processing);
+ setYearState(TransactionState.Processing);
+ unstakeAndStake(account, amount, CARMINE_STAKING_MONTH, setMonthState).then(
+ () => {
+ setSixMonthsState(TransactionState.Initial);
+ setYearState(TransactionState.Initial);
+ }
+ );
+ };
+ const handle6months = () => {
+ setMonthState(TransactionState.Processing);
+ setYearState(TransactionState.Processing);
+ unstakeAndStake(
+ account,
+ amount,
+ 6 * CARMINE_STAKING_MONTH,
+ setSixMonthsState
+ ).then(() => {
+ setMonthState(TransactionState.Initial);
+ setYearState(TransactionState.Initial);
+ });
+ };
+ const handleYear = () => {
+ setMonthState(TransactionState.Processing);
+ setSixMonthsState(TransactionState.Processing);
+ unstakeAndStake(
+ account,
+ amount,
+ 12 * CARMINE_STAKING_MONTH,
+ setYearState
+ ).then(() => {
+ setMonthState(TransactionState.Initial);
+ setSixMonthsState(TransactionState.Initial);
+ });
+ };
+
+ return (
+
+ );
+};
diff --git a/src/components/CarmineStaking/calls.ts b/src/components/CarmineStaking/calls.ts
new file mode 100644
index 00000000..9703b4c5
--- /dev/null
+++ b/src/components/CarmineStaking/calls.ts
@@ -0,0 +1,53 @@
+import { QueryFunctionContext } from "react-query";
+import { getStakes } from "../../calls/carmineStake";
+import { balanceOf } from "../../calls/balanceOf";
+import {
+ CRM_ADDRESS,
+ GOVERNANCE_ADDRESS,
+ VE_CRM_ADDRESS,
+} from "../../constants/amm";
+import { CarmineStake } from "../../classes/CarmineStake";
+import { ec, hash, shortString } from "starknet";
+import { provider } from "../../network/provider";
+
+export const fetchStakes = async ({
+ queryKey,
+}: QueryFunctionContext<[string, string]>): Promise => {
+ const address = queryKey[1];
+ return getStakes(address);
+};
+
+type StakingData = {
+ veCarmBalance: bigint;
+ carmBalance: bigint;
+ stakes: CarmineStake[];
+};
+
+export const fetchStakingData = async ({
+ queryKey,
+}: QueryFunctionContext<[string, string]>): Promise => {
+ const address = queryKey[1];
+ const promises = [
+ balanceOf(address, VE_CRM_ADDRESS),
+ balanceOf(address, CRM_ADDRESS),
+ getStakes(address),
+ ];
+ const values = await Promise.all(promises);
+ const result = {
+ veCarmBalance: values[0] as bigint,
+ carmBalance: values[1] as bigint,
+ stakes: values[2] as CarmineStake[],
+ };
+
+ return result;
+};
+
+export const readStorage = async (address: string) => {
+ const selector_airdrop_claimed = hash.keccakBn(
+ shortString.encodeShortString("airdrop_claimed")
+ );
+ const key = ec.starkCurve.pedersen(selector_airdrop_claimed, address);
+
+ const storage_value = await provider.getStorageAt(GOVERNANCE_ADDRESS, key);
+ return BigInt(storage_value);
+};
diff --git a/src/components/CarmineStaking/index.ts b/src/components/CarmineStaking/index.ts
new file mode 100644
index 00000000..700b577b
--- /dev/null
+++ b/src/components/CarmineStaking/index.ts
@@ -0,0 +1,3 @@
+import { CarmineStaking } from "./Staking";
+
+export { CarmineStaking };
diff --git a/src/components/CarmineStaking/modal.module.css b/src/components/CarmineStaking/modal.module.css
new file mode 100644
index 00000000..dfd244a1
--- /dev/null
+++ b/src/components/CarmineStaking/modal.module.css
@@ -0,0 +1,28 @@
+.modal {
+ background: black;
+ border: 1px solid white;
+ padding: 30px;
+}
+
+.modal h3 {
+ margin-top: 0;
+}
+
+.buttongroup {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+}
+
+.singlebutton {
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+}
+
+@media (max-width: 800px) {
+ .buttongroup {
+ flex-flow: column;
+ gap: 15px;
+ }
+}
\ No newline at end of file
diff --git a/src/components/CarmineStaking/vest.module.css b/src/components/CarmineStaking/vest.module.css
new file mode 100644
index 00000000..e27b9756
--- /dev/null
+++ b/src/components/CarmineStaking/vest.module.css
@@ -0,0 +1,20 @@
+.container {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+}
+
+.inputall {
+ display: flex;
+ align-items: center;
+}
+
+.inputall button {
+ border-left: 0;
+}
+
+@media (max-width: 800px) {
+ .container {
+ flex-flow: column;
+ }
+}
\ No newline at end of file
diff --git a/src/components/Slip/Slip.tsx b/src/components/Slip/Slip.tsx
index 5ea86fd5..fe2037cf 100644
--- a/src/components/Slip/Slip.tsx
+++ b/src/components/Slip/Slip.tsx
@@ -3,7 +3,8 @@ import styles from "./Slip.module.css";
const MIN_WIDTH = 1200;
-const SlipElem = () => (
+// eslint-disable-next-line @typescript-eslint/no-unused-vars
+const LegacyAppMessage = () => (
This App uses new Carmine Protocol with C2 contracts. Old App can be
accessed at{" "}
@@ -11,8 +12,17 @@ const SlipElem = () => (
);
+const AirdropMessage = () => (
+
+ Carmine Airdrop is now available! Claim it{" "}
+
here.
+
+);
+
export const Slip = () => {
- const [isWideScreen, setIsWideScreen] = useState(window.innerWidth > MIN_WIDTH);
+ const [isWideScreen, setIsWideScreen] = useState(
+ window.innerWidth > MIN_WIDTH
+ );
useEffect(() => {
function handleResize() {
@@ -25,14 +35,14 @@ export const Slip = () => {
}, []);
if (isWideScreen) {
- return ;
+ return ;
}
return (
);
diff --git a/src/components/Vesting/Vest.tsx b/src/components/Vesting/Vest.tsx
deleted file mode 100644
index 1a026710..00000000
--- a/src/components/Vesting/Vest.tsx
+++ /dev/null
@@ -1,76 +0,0 @@
-import { AccountInterface } from "starknet";
-import { useAccount } from "../../hooks/useAccount";
-import { openWalletConnectDialog } from "../ConnectWallet/Button";
-import { unVestCarm, vestCarm } from "./calls";
-import { useEffect, useState } from "react";
-import { balanceOfCarmineToken } from "../../calls/balanceOf";
-import { Skeleton } from "@mui/material";
-import { shortInteger } from "../../utils/computations";
-import styles from "./vest.module.css";
-import inputStyles from "../../style/input.module.css";
-
-export const VestWithAccount = ({ account }: { account: AccountInterface }) => {
- const [carmBalance, setCarmBalance] = useState(undefined);
- const [inputValue, setInputValue] = useState("");
-
- useEffect(() => {
- balanceOfCarmineToken(account).then((b) =>
- setCarmBalance(shortInteger(b, 18))
- );
- }, [account]);
-
- if (carmBalance === undefined) {
- return (
-
-
-
-
- );
- }
-
- const handleInputChange = (value: string) => {
- // Allow empty string, valid number, or a single decimal point followed by numbers
- const numericValue =
- value === "" || /^\d*\.?\d{0,6}$/.test(value) ? value : inputValue;
-
- const num = parseFloat(numericValue);
-
- if (num && num > carmBalance) {
- // cannot set more than holds
- return;
- }
-
- setInputValue(numericValue);
- };
-
- return (
-
-
- You have 0 CARM and {carmBalance.toFixed(5)} veCarm
-
-
Stake your CARM for a period
-
- handleInputChange(e.target.value)}
- />
-
-
-
-
-
- );
-};
-
-export const Vest = () => {
- const account = useAccount();
-
- if (!account) {
- return ;
- }
-
- return ;
-};
diff --git a/src/components/Vesting/calls.ts b/src/components/Vesting/calls.ts
deleted file mode 100644
index 2e09329e..00000000
--- a/src/components/Vesting/calls.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export const vestCarm = () => {
- console.log("Vesting...");
-};
-
-export const unVestCarm = () => {
- console.log("UnVesting...");
-};
diff --git a/src/components/Vesting/index.ts b/src/components/Vesting/index.ts
deleted file mode 100644
index 090815a7..00000000
--- a/src/components/Vesting/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-import { Vest } from "./Vest";
-
-export { Vest };
diff --git a/src/components/Vesting/vest.module.css b/src/components/Vesting/vest.module.css
deleted file mode 100644
index aaa7ce95..00000000
--- a/src/components/Vesting/vest.module.css
+++ /dev/null
@@ -1,5 +0,0 @@
-.container {
- display: flex;
- align-items: center;
- gap: 1rem;
-}
\ No newline at end of file
diff --git a/src/constants/amm.ts b/src/constants/amm.ts
index 3e8fc74c..4b32a24f 100644
--- a/src/constants/amm.ts
+++ b/src/constants/amm.ts
@@ -8,6 +8,8 @@ export const ETH_ADDRESS = config.ETH_ADDRESS;
export const USDC_ADDRESS = config.USDC_ADDRESS;
export const BTC_ADDRESS = config.BTC_ADDRESS;
export const STRK_ADDRESS = config.STRK_ADDRESS;
+export const VE_CRM_ADDRESS = config.VE_CRM_ADDRESS;
+export const CRM_ADDRESS = config.CRM_ADDRESS;
export const ETH_USDC_CALL_ADDRESS = config.ETH_USDC_CALL_ADDRESS;
export const ETH_USDC_PUT_ADDRESS = config.ETH_USDC_PUT_ADDRESS;
export const BTC_USDC_CALL_ADDRESS = config.BTC_USDC_CALL_ADDRESS;
@@ -72,3 +74,5 @@ export const USDC_BASE_VALUE = BigInt(10) ** BigInt(USDC_DIGITS);
export const BASE_MATH_64_61 = BigInt(2) ** BigInt(61);
export const BASE_MATH_64 = BigInt(2) ** BigInt(64);
export const USDC_PRECISSION = 1000;
+
+export const CARMINE_STAKING_MONTH = 2629743;
diff --git a/src/constants/config.json b/src/constants/config.json
index 63f1567d..1fd8caa0 100644
--- a/src/constants/config.json
+++ b/src/constants/config.json
@@ -7,6 +7,8 @@
"USDC_ADDRESS": "0x053c91253bc9682c04929ca02ed00b3e423f6710d2ee7e0d5ebb06f3ecf368a8",
"BTC_ADDRESS": "0x03fe2b97c1fd336e750087d68b9b867997fd64a2661ff3ca5a7c771641e8e7ac",
"STRK_ADDRESS": "0x04718f5a0fc34cc1af16a1cdee98ffb20c31f5cd61d6ab07201858f4287c938d",
+ "VE_CRM_ADDRESS": "0x3c0286e9e428a130ae7fbbe911b794e8a829c367dd788e7cfe3efb0367548fa",
+ "CRM_ADDRESS": "0x51c4b1fe3bf6774b87ad0b15ef5d1472759076e42944fff9b9f641ff13e5bbe",
"ETH_USDC_CALL_ADDRESS": "0x70cad6be2c3fc48c745e4a4b70ef578d9c79b46ffac4cd93ec7b61f951c7c5c",
"ETH_USDC_PUT_ADDRESS": "0x466e3a6731571cf5d74c5b0d9c508bfb71438de10f9a13269177b01d6f07159",
"BTC_USDC_CALL_ADDRESS": "0x35db72a814c9b30301f646a8fa8c192ff63a0dc82beb390a36e6e9eba55b6db",
diff --git a/src/constants/starknet.ts b/src/constants/starknet.ts
index eb0c8a8b..823e7593 100644
--- a/src/constants/starknet.ts
+++ b/src/constants/starknet.ts
@@ -1 +1,13 @@
+import { Contract } from "starknet";
+import { GOVERNANCE_ADDRESS } from "./amm";
+import { provider } from "../network/provider";
+
+import GovernanceABI from "../abi/governance_abi.json";
+
export const TESTNET_CHAINID = "0x534e5f474f45524c49";
+
+export const governanceContract = new Contract(
+ GovernanceABI,
+ GOVERNANCE_ADDRESS,
+ provider
+);
diff --git a/src/network/provider.ts b/src/network/provider.ts
index 8817dd70..fdabe8e1 100644
--- a/src/network/provider.ts
+++ b/src/network/provider.ts
@@ -14,6 +14,7 @@ export const testnetOptions: RpcProviderOptions = {
export const mainnetOptions: RpcProviderOptions = {
nodeUrl: apiUrl("call", { network: "mainnet" }),
+ // nodeUrl: "http://34.22.208.73:5051", dev mainnet
chainId: constants.StarknetChainId.SN_MAIN,
};
diff --git a/src/pages/governance.tsx b/src/pages/governance.tsx
index 11a6934c..2ed3156f 100644
--- a/src/pages/governance.tsx
+++ b/src/pages/governance.tsx
@@ -2,13 +2,14 @@ import { Helmet } from "react-helmet";
import { Layout } from "../components/Layout";
import { Proposals } from "../components/Proposal";
-import { Vest } from "../components/Vesting";
+import { CarmineStaking } from "../components/CarmineStaking";
import { useGovernanceSubpage } from "../hooks/useGovernanceSubpage";
import { GovernanceSubpage } from "../redux/reducers/ui";
import { useNavigate } from "react-router-dom";
import buttonStyles from "../style/button.module.css";
import { setGovernanceSubpage } from "../redux/actions";
import { Airdrop } from "../components/Airdrop/Airdrop";
+import { useEffect } from "react";
const VotingSubpage = () => {
return (
@@ -23,11 +24,8 @@ const VotingSubpage = () => {
const StakingSubpage = () => {
return (
-
CARM Staking
-
- Stake your CARM
-
-
+
CRM Staking
+
);
};
@@ -36,6 +34,20 @@ const Governance = () => {
const subpage = useGovernanceSubpage();
const navigate = useNavigate();
+ useEffect(() => {
+ const parts = window.location.pathname.split("/").filter((s) => s !== "");
+
+ if (
+ parts.length === 2 &&
+ Object.values(GovernanceSubpage).includes(
+ parts[1] as GovernanceSubpage
+ ) &&
+ (parts[1] as GovernanceSubpage) !== subpage
+ ) {
+ setGovernanceSubpage(parts[1] as GovernanceSubpage);
+ }
+ });
+
const handleNavigateClick = (subpage: GovernanceSubpage) => {
setGovernanceSubpage(subpage);
navigate(`/governance/${subpage}`);
diff --git a/src/queries/client.ts b/src/queries/client.ts
index 4013c9d2..121e837b 100644
--- a/src/queries/client.ts
+++ b/src/queries/client.ts
@@ -18,3 +18,5 @@ export const invalidatePositions = () =>
queryClient.invalidateQueries(QueryKeys.position);
export const invalidateStake = () =>
queryClient.invalidateQueries(QueryKeys.stake);
+export const invalidateKey = (queryKey: QueryKeys) =>
+ queryClient.invalidateQueries(queryKey);
diff --git a/src/queries/keys.ts b/src/queries/keys.ts
index 25892ca9..e4e372f3 100644
--- a/src/queries/keys.ts
+++ b/src/queries/keys.ts
@@ -10,4 +10,6 @@ export enum QueryKeys {
userPoints = "USER_POINTS",
braavosBonus = "BRAAVOS_BONUS",
defiSpringClaimed = "DEFI_SPRING_CLAIMED",
+ carmineStakes = "CARMINE_STAKES",
+ airdropData = "AIRDROP_DATA",
}
diff --git a/src/redux/reducers/transactions.ts b/src/redux/reducers/transactions.ts
index 9684e4dc..5b540ac7 100644
--- a/src/redux/reducers/transactions.ts
+++ b/src/redux/reducers/transactions.ts
@@ -11,6 +11,8 @@ export enum TransactionAction {
Vote = "Vote",
Swap = "Swap",
ClaimReward = "ClaimReward",
+ CarmineStake = "CarmineStake",
+ CarmineUnstake = "CarmineUnstake",
}
export enum TransactionStatus {
diff --git a/src/style/button.module.css b/src/style/button.module.css
index 8be30455..9f21fd25 100644
--- a/src/style/button.module.css
+++ b/src/style/button.module.css
@@ -8,6 +8,11 @@
color: #1aff00;
}
+.fail {
+ border: 2px solid #ad1111;
+ color: #ad1111;
+}
+
.disabled {
border: 2px solid rgba(160, 160, 160, .6);
color: rgba(160, 160, 160, .6);
diff --git a/src/style/input.module.css b/src/style/input.module.css
index 6c50b66f..b3b70b35 100644
--- a/src/style/input.module.css
+++ b/src/style/input.module.css
@@ -5,7 +5,7 @@
font-size: 21px;
padding: 3px 15px;
text-align: center;
- height: 46px;
+ height: 50px;
max-width: 150px;
}
diff --git a/src/types/governance.ts b/src/types/governance.ts
new file mode 100644
index 00000000..5e3070c2
--- /dev/null
+++ b/src/types/governance.ts
@@ -0,0 +1,7 @@
+export type CarmineStakeResult = {
+ amount_staked: bigint;
+ amount_voting_token: bigint;
+ start_date: bigint;
+ length: bigint;
+ withdrawn: boolean;
+};
diff --git a/src/types/network.ts b/src/types/network.ts
index 5abb7196..45875eb7 100644
--- a/src/types/network.ts
+++ b/src/types/network.ts
@@ -19,3 +19,12 @@ export interface NetworkState {
provider: RpcProvider;
network: Network;
}
+
+export enum TransactionState {
+ Initial,
+ Processing,
+ Success,
+ Fail,
+}
+
+export type TxTracking = (s: TransactionState) => void;
From 778f4f11688bc4beed33ce884c705cc7fe06f659 Mon Sep 17 00:00:00 2001
From: DaveVodrazka
Date: Thu, 27 Jun 2024 13:10:44 +0200
Subject: [PATCH 04/20] fix: airdrop texts
---
src/components/Airdrop/Airdrop.tsx | 3 +--
src/components/Airdrop/airdrop.module.css | 7 +++++++
src/components/CarmineStaking/Staking.tsx | 13 +++++++++----
3 files changed, 17 insertions(+), 6 deletions(-)
diff --git a/src/components/Airdrop/Airdrop.tsx b/src/components/Airdrop/Airdrop.tsx
index c23b1557..d43975d1 100644
--- a/src/components/Airdrop/Airdrop.tsx
+++ b/src/components/Airdrop/Airdrop.tsx
@@ -9,7 +9,6 @@ import { isMainnet } from "../../constants/amm";
import { QueryKeys } from "../../queries/keys";
import { AirdropModal } from "./AirdropModal";
-import styles from "../../style/table.module.css";
import buttonStyles from "../../style/button.module.css";
import airdropStyles from "./airdrop.module.css";
@@ -50,7 +49,7 @@ const ClaimAndStake = ({
const AirdropTemplate = ({ message }: { message: string }) => (
Airdrop
-
{message}
+
{message}
);
diff --git a/src/components/Airdrop/airdrop.module.css b/src/components/Airdrop/airdrop.module.css
index 1d7b5157..10537927 100644
--- a/src/components/Airdrop/airdrop.module.css
+++ b/src/components/Airdrop/airdrop.module.css
@@ -5,6 +5,13 @@
padding: 25px 50px;
}
+.textcontainer {
+ flex-flow: row;
+ border: 1px solid white;
+ padding: 25px 50px;
+ display: inline-block;
+}
+
.claim {
border: 1px solid white;
display: inline-flex;
diff --git a/src/components/CarmineStaking/Staking.tsx b/src/components/CarmineStaking/Staking.tsx
index d2bb1a40..45fd9ebe 100644
--- a/src/components/CarmineStaking/Staking.tsx
+++ b/src/components/CarmineStaking/Staking.tsx
@@ -35,17 +35,22 @@ export const StakeWithAccount = ({
return (
- Find out more about CRM staking and veCRM{" "}
-
- insert some link here
+ Want to know more about CRM staking and veCRM?{" "}
+
+ Find out here!
.
+
You have {humanReadableCarmBalance} CRM and{" "}
{humanReadableVeCarmBalance} veCRM
- {carmBalance >= 0n && (
+ {carmBalance > 0n && (
)}
From 3454e2f0e1bfc8c7e8e2a48c7054738b1f9152f6 Mon Sep 17 00:00:00 2001
From: DaveVodrazka
Date: Thu, 27 Jun 2024 13:18:12 +0200
Subject: [PATCH 05/20] fix: slip with routing
---
src/App.tsx | 2 +-
src/components/Slip/Slip.tsx | 22 ++++++++++++++++------
2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/src/App.tsx b/src/App.tsx
index 0114908a..6d738a03 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -45,8 +45,8 @@ const App = () => {
{acceptedTermsAndConditions ? (
<>
-
+
{oldPathRedirects.map(([oldPath, newPath], i) => (
(
);
-const AirdropMessage = () => (
-
- Carmine Airdrop is now available! Claim it{" "}
-
here.
-
-);
+const AirdropMessage = () => {
+ const navigate = useNavigate();
+
+ const handleClick = () => navigate("/governance/airdrop");
+
+ return (
+
+ Carmine Airdrop is now available! Claim it{" "}
+
+ here
+
+ .
+
+ );
+};
export const Slip = () => {
const [isWideScreen, setIsWideScreen] = useState(
From d94fa3d4b2c522248362af23ed48e10424d4a26c Mon Sep 17 00:00:00 2001
From: DaveVodrazka
Date: Thu, 27 Jun 2024 13:29:15 +0200
Subject: [PATCH 06/20] fix: select size stake modal
---
.../CarmineStaking/StakingModal.tsx | 125 ++++++++++++------
.../CarmineStaking/modal.module.css | 15 +++
2 files changed, 98 insertions(+), 42 deletions(-)
diff --git a/src/components/CarmineStaking/StakingModal.tsx b/src/components/CarmineStaking/StakingModal.tsx
index ca253c10..86d5a9e5 100644
--- a/src/components/CarmineStaking/StakingModal.tsx
+++ b/src/components/CarmineStaking/StakingModal.tsx
@@ -1,7 +1,7 @@
import { Dialog } from "@mui/material";
import { AccountInterface } from "starknet";
-import { shortInteger } from "../../utils/computations";
+import { longInteger, shortInteger } from "../../utils/computations";
import { CARMINE_STAKING_MONTH, GOVERNANCE_ADDRESS } from "../../constants/amm";
import GovernanceABI from "../../abi/governance_abi.json";
import {
@@ -20,6 +20,7 @@ import { unstakeAirdrop } from "../../calls/carmineStake";
import styles from "./modal.module.css";
import buttonStyles from "../../style/button.module.css";
+import inputStyles from "../../style/input.module.css";
export const unstakeAndStake = async (
account: AccountInterface,
@@ -88,6 +89,8 @@ export const stateToClassName = (state: TransactionState) => {
};
export const StakingModal = ({ account, amount, open, setOpen }: Props) => {
+ const numCarmBalance = shortInteger(amount, 18);
+ const [inputValue, setInputValue] = useState(numCarmBalance.toString(10));
const [unstakeState, setUnstakeState] = useState(TransactionState.Initial);
const [monthState, setMonthState] = useState(TransactionState.Initial);
const [sixMonthsState, setSixMonthsState] = useState(
@@ -95,6 +98,8 @@ export const StakingModal = ({ account, amount, open, setOpen }: Props) => {
);
const [yearState, setYearState] = useState(TransactionState.Initial);
+ const selectedAmount = longInteger(parseFloat(inputValue), 18);
+
const handleClose = () => {
setOpen(false);
setUnstakeState(TransactionState.Initial);
@@ -108,19 +113,22 @@ export const StakingModal = ({ account, amount, open, setOpen }: Props) => {
const handle1month = () => {
setSixMonthsState(TransactionState.Processing);
setYearState(TransactionState.Processing);
- unstakeAndStake(account, amount, CARMINE_STAKING_MONTH, setMonthState).then(
- () => {
- setSixMonthsState(TransactionState.Initial);
- setYearState(TransactionState.Initial);
- }
- );
+ unstakeAndStake(
+ account,
+ selectedAmount,
+ CARMINE_STAKING_MONTH,
+ setMonthState
+ ).then(() => {
+ setSixMonthsState(TransactionState.Initial);
+ setYearState(TransactionState.Initial);
+ });
};
const handle6months = () => {
setMonthState(TransactionState.Processing);
setYearState(TransactionState.Processing);
unstakeAndStake(
account,
- amount,
+ selectedAmount,
6 * CARMINE_STAKING_MONTH,
setSixMonthsState
).then(() => {
@@ -133,7 +141,7 @@ export const StakingModal = ({ account, amount, open, setOpen }: Props) => {
setSixMonthsState(TransactionState.Processing);
unstakeAndStake(
account,
- amount,
+ selectedAmount,
12 * CARMINE_STAKING_MONTH,
setYearState
).then(() => {
@@ -142,6 +150,23 @@ export const StakingModal = ({ account, amount, open, setOpen }: Props) => {
});
};
+ const handleInputChange = (value: string) => {
+ // Allow empty string, valid number, or a single decimal point followed by numbers
+ const numericValue =
+ value === "" || /^\d*\.?\d{0,6}$/.test(value) ? value : inputValue;
+
+ const num = parseFloat(numericValue);
+
+ if (num && num > numCarmBalance) {
+ // cannot set more than holds
+ return;
+ }
+
+ setInputValue(numericValue);
+ };
+
+ const handleAll = () => setInputValue(numCarmBalance.toString(10));
+
return (
You can stake again for a period:
-