From 529a1f13d5d21f7540406ce449312076e99b4c1e Mon Sep 17 00:00:00 2001 From: user Date: Mon, 18 Dec 2023 17:49:22 +1030 Subject: [PATCH 01/18] Initial changes to support airdrop v2 --- .../JoeFarmlandsOrCamelotKingdom/index.tsx | 26 ++++ .../JoeFarmlandsOrCamelotKingdom/styles.css | 32 +++++ .../app/components/index.ts | 1 + web/app.fluidity.money/app/root.tsx | 3 +- .../$network/dashboard/airdrop/index.tsx | 129 ++---------------- .../app/styles/dashboard.css | 30 +--- .../app/styles/dashboard/airdrop.css | 85 ++---------- .../app/styles/dashboard/airdrop.scss | 6 - .../app/styles/transfer.css | 15 +- .../public/images/epoch2AirdropBanner.png | 3 + .../public/images/joe-farmlands.png | 3 + .../public/images/kingdom-of-camelot.png | 3 + .../public/images/providers/Jumper.svg | 3 + .../public/images/providers/Ramses.svg | 3 + 14 files changed, 103 insertions(+), 239 deletions(-) create mode 100644 web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx create mode 100644 web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css create mode 100644 web/app.fluidity.money/public/images/epoch2AirdropBanner.png create mode 100644 web/app.fluidity.money/public/images/joe-farmlands.png create mode 100644 web/app.fluidity.money/public/images/kingdom-of-camelot.png create mode 100644 web/app.fluidity.money/public/images/providers/Jumper.svg create mode 100644 web/app.fluidity.money/public/images/providers/Ramses.svg diff --git a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx new file mode 100644 index 000000000..5be892e19 --- /dev/null +++ b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx @@ -0,0 +1,26 @@ + +import styles from "./styles.css"; + +export const JoeFarmlandsOrCamelotKingdomLinks = () => [{ rel: "stylesheet", href: styles }]; + +interface IJoeFarmlandsOrCamelotKingdomProps { +}; + +const JoeFarmlandsOrCamelotKingdom = (props: IJoeFarmlandsOrCamelotKingdomProps) => { + return ( +
+ + + + + + +
+ ); +} + +export default JoeFarmlandsOrCamelotKingdom; diff --git a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css new file mode 100644 index 000000000..3b8e34bf9 --- /dev/null +++ b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css @@ -0,0 +1,32 @@ + +.joe_farmlands_or_camelot_div { + padding-top: 20px; +} + +.joe_farmlands_or_camelot_div img { + position: absolute; + width: 100%; + border-radius: 10px; +} + +.joe_farmlands_or_camelot_img_joe { + clip-path: polygon(0% 0%, 0% 100%, 100% 0%); +} + +.joe_farmlands_or_camelot_img_camelot { + padding-top: 12px; + clip-path: polygon(100% 0, 0% 100%, 100% 100%); +} + +.joe_farmlands_or_camelot_div img:hover { + transform-origin: 50% 50% 0; + animation: joe_farmlands_or_camelot_img_scale 100ms ease-in-out forwards; + z-index: -999; +} + +@keyframes joe_farmlands_or_camelot_img_scale { + to { + transform: scale(1.025); + filter: drop-shadow(0px 0px 0px #333); + } +} diff --git a/web/app.fluidity.money/app/components/index.ts b/web/app.fluidity.money/app/components/index.ts index df7ea69c4..268d18965 100644 --- a/web/app.fluidity.money/app/components/index.ts +++ b/web/app.fluidity.money/app/components/index.ts @@ -6,3 +6,4 @@ export { ToolTipContent, } from "./ToolTip"; export { UtilityToken } from "./UtilityToken"; +export { JoeFarmlandsOrCamelotKingdomLinks } from "./JoeFarmlandsOrCamelotKingdom"; diff --git a/web/app.fluidity.money/app/root.tsx b/web/app.fluidity.money/app/root.tsx index 819c7a8cd..323475f24 100644 --- a/web/app.fluidity.money/app/root.tsx +++ b/web/app.fluidity.money/app/root.tsx @@ -15,7 +15,7 @@ import { withSentry } from "@sentry/remix"; import globalStylesheetUrl from "./global-styles.css"; import surfingStylesheetUrl from "@fluidity-money/surfing/dist/style.css"; -import { ToolTipLinks } from "./components"; +import { JoeFarmlandsOrCamelotKingdomLinks,ToolTipLinks } from "./components"; import { ToolProvider } from "./components/ToolTip"; import { SplitContextProvider } from "contexts/SplitProvider"; import CacheProvider from "contexts/CacheProvider"; @@ -29,6 +29,7 @@ globalThis.Buffer = Buffer; export const links = () => { return [ ...ToolTipLinks(), + ...JoeFarmlandsOrCamelotKingdomLinks(), { rel: "icon", href: "/favicon.ico" }, { rel: "apple-touch-icon", sizes: "57x57", href: "/apple-icon-57x57.png" }, diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx index ea43bf3f2..a818d7528 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx @@ -57,6 +57,7 @@ import { useCache } from "~/hooks/useCache"; import Table, { IRow } from "~/components/Table"; import { ReferralBottlesCountLoaderData } from "../../query/referralBottles"; import { HowItWorksContent } from "~/components/ReferralModal"; +import JoeFarmlandsOrCamelotKingdom from "~/components/JoeFarmlandsOrCamelotKingdom"; const EPOCH_DAYS_TOTAL = 38; // temp: may 22nd, 2023 @@ -293,7 +294,7 @@ const Airdrop = () => { const destModal = location.hash.replace("#", ""); const [currentModal, setCurrentModal] = useState( - isAirdropModal(destModal) ? destModal : "recap" + isAirdropModal(destModal) ? destModal : null ); useEffect(() => { @@ -520,7 +521,7 @@ const Airdrop = () => { groupId="airdrop" isSelected={currentModal === "recap"} > - Airdrop Recap + Epoch 1 Recap { {currentModal === null && ( <>
+ )} -
- MY TOTAL LIQUIDITY MULTIPLIER} - > - - {toSignificantDecimals(sumLiquidityMultiplier, 1)}x - - -
} layout="after" @@ -1358,112 +1349,14 @@ const MyMultiplier = ({ handleClick={seeMyStakingStats} id="mx-see-my-staking-stats" > - MY STAKING STATS - - {!isMobile && ( -
- {stakes - .map((stake) => { - const { fluidAmount, baseAmount, durationDays, depositDate } = - stake; - - const stakedDays = dayDifference( - new Date(), - new Date(depositDate) - ); - const multiplier = stakingLiquidityMultiplierEq( - stakedDays, - durationDays - ); - - const fluidDecimals = 6; - const fluidUsd = getUsdFromTokenAmount( - fluidAmount, - fluidDecimals, - usdcPrice - ); - - const wethDecimals = 18; - const usdcDecimals = 6; - - // If converting base amount by weth decimals (18) is smaller than $0.01, - // then tentatively assume Token amount is USDC - // A false hit would be a USDC deposit >= $100,000 - const baseUsd = - getUsdFromTokenAmount(baseAmount, wethDecimals, wethPrice) < - 0.01 - ? getUsdFromTokenAmount(baseAmount, usdcDecimals, usdcPrice) - : getUsdFromTokenAmount(baseAmount, wethDecimals, wethPrice); - - return { - stake, - stakedDays, - multiplier, - fluidUsd, - baseUsd, - }; - }) - .sort((a, b) => { - const stakeAVal = (a.fluidUsd + a.baseUsd) * a.multiplier; - const stakeBVal = (b.fluidUsd + b.baseUsd) * b.multiplier; - - // Sort Descending - return stakeBVal > stakeAVal - ? 1 - : stakeBVal === stakeAVal - ? 0 - : -1; - }) - .slice(0, 3) - .map(({ stake, multiplier, fluidUsd, baseUsd }) => { - const { durationDays } = stake; - - return ( - <> -
- - {numberToMonetaryString(fluidUsd + baseUsd)} FOR{" "} - {Math.floor(durationDays)} DAYS - - -
-
- - {toSignificantDecimals(multiplier, 1)}X - -
- - ); - })} -
- )} - : undefined} - layout={"after"} - buttontype="text" - size="medium" - version="primary" - handleClick={seeStakeNow} - id="mx-stake-now-button" - disabled={true} - > - STAKE NOW + MY EPOCH 1 STAKING STATS +
+ + Provide $fUSDC Liquidity to earn $ARB and Multipliers! + + +
); }; diff --git a/web/app.fluidity.money/app/styles/dashboard.css b/web/app.fluidity.money/app/styles/dashboard.css index f5c50dbf0..ede067258 100644 --- a/web/app.fluidity.money/app/styles/dashboard.css +++ b/web/app.fluidity.money/app/styles/dashboard.css @@ -149,20 +149,7 @@ body { background-repeat: no-repeat; background-size: 100%; background-position: 0 0, 100% 0, 100% 100%, 0 100%; - background-image: linear-gradient( - 45deg, - #f3b8d8, - #b793e9, - #9fd4f3, - #ffd2c4, - #fbf3f3, - #d9abdf, - #af9ce3, - #aae4e1, - #c6ead0, - #ffffff, - #fdb5e4 - ); + background-image: linear-gradient(45deg, #f3b8d8, #b793e9, #9fd4f3, #ffd2c4, #fbf3f3, #d9abdf, #af9ce3, #aae4e1, #c6ead0, #ffffff, #fdb5e4); animation: rotate 4s linear infinite; } @@ -630,20 +617,7 @@ ul.sidebar-nav li div.active { } .holo { - background: conic-gradient( - from 209.59deg at 50% 50%, - #f3b8d8 0deg, - #b793e9 50.06deg, - #9fd4f3 85.94deg, - #ffd2c4 134.97deg, - #fbf3f3 172.05deg, - #d9abdf 200.75deg, - #af9ce3 224.67deg, - #aae4e1 259.36deg, - #c6ead0 298.82deg, - #ffffff 328.72deg, - #fdb5e4 360deg - ); + background: conic-gradient(from 209.59deg at 50% 50%, #f3b8d8 0deg, #b793e9 50.06deg, #9fd4f3 85.94deg, #ffd2c4 134.97deg, #fbf3f3 172.05deg, #d9abdf 200.75deg, #af9ce3 224.67deg, #aae4e1 259.36deg, #c6ead0 298.82deg, #ffffff 328.72deg, #fdb5e4 360deg); height: 40px; width: 40px; border-radius: 50%; diff --git a/web/app.fluidity.money/app/styles/dashboard/airdrop.css b/web/app.fluidity.money/app/styles/dashboard/airdrop.css index a75578573..fb841c4bf 100644 --- a/web/app.fluidity.money/app/styles/dashboard/airdrop.css +++ b/web/app.fluidity.money/app/styles/dashboard/airdrop.css @@ -273,19 +273,7 @@ } .transaction-table > thead > tr.highlighted-row, .transaction-table > tbody > tr.airdrop-row.highlighted-row { - background: linear-gradient( - 90deg, - #f3b8d8 0%, - #b793e9 15.1%, - #9fd4f3 26.04%, - #ffd2c4 36.46%, - #fbf3f3 46.88%, - #d9abdf 57.29%, - #af9ce3 72.4%, - #aae4e1 85.42%, - #c6ead0 93.23%, - #fdb5e4 100% - ); + background: linear-gradient(90deg, #f3b8d8 0%, #b793e9 15.1%, #9fd4f3 26.04%, #ffd2c4 36.46%, #fbf3f3 46.88%, #d9abdf 57.29%, #af9ce3 72.4%, #aae4e1 85.42%, #c6ead0 93.23%, #fdb5e4 100%); } .transaction-table > thead > tr.highlighted-row td, .transaction-table > tbody > tr.airdrop-row.highlighted-row td { @@ -314,30 +302,14 @@ } .airdrop-leaderboard-mobile .transaction-table > thead > tr td:first-child, .airdrop-leaderboard-mobile .transaction-table > thead > tr th:first-child, -.airdrop-leaderboard-mobile - .transaction-table - > tbody - > tr.airdrop-row - td:first-child, -.airdrop-leaderboard-mobile - .transaction-table - > tbody - > tr.airdrop-row - th:first-child { +.airdrop-leaderboard-mobile .transaction-table > tbody > tr.airdrop-row td:first-child, +.airdrop-leaderboard-mobile .transaction-table > tbody > tr.airdrop-row th:first-child { padding-left: 1em; } .airdrop-leaderboard-mobile .transaction-table > thead > tr td:last-child, .airdrop-leaderboard-mobile .transaction-table > thead > tr th:last-child, -.airdrop-leaderboard-mobile - .transaction-table - > tbody - > tr.airdrop-row - td:last-child, -.airdrop-leaderboard-mobile - .transaction-table - > tbody - > tr.airdrop-row - th:last-child { +.airdrop-leaderboard-mobile .transaction-table > tbody > tr.airdrop-row td:last-child, +.airdrop-leaderboard-mobile .transaction-table > tbody > tr.airdrop-row th:last-child { padding-right: 1em; } .airdrop-leaderboard-mobile .transaction-table > thead > tr td, @@ -391,9 +363,6 @@ .airdrop-my-multiplier { position: relative; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 2em; } .airdrop-my-multiplier svg, .airdrop-my-multiplier path { @@ -426,9 +395,6 @@ } .airdrop-my-multiplier #mx-see-my-staking-stats { width: 100%; - grid-area: 2/1; - box-sizing: border-box; - align-self: end; } .airdrop-my-multiplier #mx-my-stakes { display: grid; @@ -714,10 +680,7 @@ align-items: flex-start; gap: 0.5em; } -.staking-stats-container - .staking-stats-stakes-container - .stake - .stake-multiplier { +.staking-stats-container .staking-stats-stakes-container .stake .stake-multiplier { width: 100%; display: flex; flex-wrap: wrap; @@ -790,31 +753,18 @@ width: 150px; height: 150px; } -.recap-container - .recap-hero - .recap-hero-text - .recap-circle-scroll - .recap-circle-scroll-arrow { +.recap-container .recap-hero .recap-hero-text .recap-circle-scroll .recap-circle-scroll-arrow { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } -.recap-container - .recap-hero - .recap-hero-text - .recap-circle-scroll - .recap-circle-scroll-arrow - svg { +.recap-container .recap-hero .recap-hero-text .recap-circle-scroll .recap-circle-scroll-arrow svg { fill: none; stroke: white; transform: scale(3); } -.recap-container - .recap-hero - .recap-hero-text - .recap-circle-scroll - .recap-circle-scroll-text { +.recap-container .recap-hero .recap-hero-text .recap-circle-scroll .recap-circle-scroll-text { font-size: 10px; fill: grey; letter-spacing: 0.4em; @@ -906,28 +856,19 @@ /* Track */ /* Handle */ } -.recap-container - .recap-stats - .recap-bottle-distribution-container::-webkit-scrollbar { +.recap-container .recap-stats .recap-bottle-distribution-container::-webkit-scrollbar { height: 10px; } -.recap-container - .recap-stats - .recap-bottle-distribution-container::-webkit-scrollbar-track { +.recap-container .recap-stats .recap-bottle-distribution-container::-webkit-scrollbar-track { background: transparent; border: 1px solid white; border-radius: 5px; } -.recap-container - .recap-stats - .recap-bottle-distribution-container::-webkit-scrollbar-thumb { +.recap-container .recap-stats .recap-bottle-distribution-container::-webkit-scrollbar-thumb { background: white; border-radius: 5px; } -.recap-container - .recap-stats - .recap-bottle-distribution-container - .bottle-container { +.recap-container .recap-stats .recap-bottle-distribution-container .bottle-container { gap: 1em; display: flex; flex-direction: column; diff --git a/web/app.fluidity.money/app/styles/dashboard/airdrop.scss b/web/app.fluidity.money/app/styles/dashboard/airdrop.scss index bb43ffe2e..532b157c9 100644 --- a/web/app.fluidity.money/app/styles/dashboard/airdrop.scss +++ b/web/app.fluidity.money/app/styles/dashboard/airdrop.scss @@ -400,9 +400,6 @@ $holo: linear-gradient( .airdrop-my-multiplier { position: relative; - display: grid; - grid-template-columns: 1fr 1fr; - gap: 2em; svg, path { @@ -442,9 +439,6 @@ $holo: linear-gradient( #mx-see-my-staking-stats { width: 100%; - grid-area: 2 / 1; - box-sizing: border-box; - align-self: end; } #mx-my-stakes { diff --git a/web/app.fluidity.money/app/styles/transfer.css b/web/app.fluidity.money/app/styles/transfer.css index 0d4055653..337cd2928 100644 --- a/web/app.fluidity.money/app/styles/transfer.css +++ b/web/app.fluidity.money/app/styles/transfer.css @@ -276,20 +276,7 @@ body { right: 0; bottom: 0; z-index: 1; - background: conic-gradient( - from 209.59deg at 50% 50%, - #f3b8d8 0deg, - #b793e9 50.06deg, - #9fd4f3 85.94deg, - #ffd2c4 134.97deg, - #fbf3f3 172.05deg, - #d9abdf 200.75deg, - #af9ce3 224.67deg, - #aae4e1 259.36deg, - #c6ead0 298.82deg, - #ffffff 328.72deg, - #fdb5e4 360deg - ); + background: conic-gradient(from 209.59deg at 50% 50%, #f3b8d8 0deg, #b793e9 50.06deg, #9fd4f3 85.94deg, #ffd2c4 134.97deg, #fbf3f3 172.05deg, #d9abdf 200.75deg, #af9ce3 224.67deg, #aae4e1 259.36deg, #c6ead0 298.82deg, #ffffff 328.72deg, #fdb5e4 360deg); filter: blur(10px); scale: 1.1; } diff --git a/web/app.fluidity.money/public/images/epoch2AirdropBanner.png b/web/app.fluidity.money/public/images/epoch2AirdropBanner.png new file mode 100644 index 000000000..4e001da53 --- /dev/null +++ b/web/app.fluidity.money/public/images/epoch2AirdropBanner.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c62d475e73da37820d1653cbca3f8318cfcea7eb2869e639a61c83805727a397 +size 696368 diff --git a/web/app.fluidity.money/public/images/joe-farmlands.png b/web/app.fluidity.money/public/images/joe-farmlands.png new file mode 100644 index 000000000..4a1b50dbd --- /dev/null +++ b/web/app.fluidity.money/public/images/joe-farmlands.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2395663fa922328621ea843e25ca3ad697d61c2414bb6a18b3bb57c2c577140d +size 248359 diff --git a/web/app.fluidity.money/public/images/kingdom-of-camelot.png b/web/app.fluidity.money/public/images/kingdom-of-camelot.png new file mode 100644 index 000000000..5e33cf3f3 --- /dev/null +++ b/web/app.fluidity.money/public/images/kingdom-of-camelot.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e623e4cabc261485889e786d0624b00466829912c28b43b8e2678b59df78ffb4 +size 131162 diff --git a/web/app.fluidity.money/public/images/providers/Jumper.svg b/web/app.fluidity.money/public/images/providers/Jumper.svg new file mode 100644 index 000000000..d7f19b72e --- /dev/null +++ b/web/app.fluidity.money/public/images/providers/Jumper.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:60185b2e2158d5c994f8665081a708e721849bc038e4decdc36bbb64bf171446 +size 1180 diff --git a/web/app.fluidity.money/public/images/providers/Ramses.svg b/web/app.fluidity.money/public/images/providers/Ramses.svg new file mode 100644 index 000000000..492f06864 --- /dev/null +++ b/web/app.fluidity.money/public/images/providers/Ramses.svg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3519ca5687a2779d0ad4af62ffbff2bf2eeb5ec2f5ff6ca53593254a3ec9e00e +size 2668 From a4af17f0d69807ac8bd18beb11019f153b478cac Mon Sep 17 00:00:00 2001 From: user Date: Tue, 19 Dec 2023 09:43:06 +1030 Subject: [PATCH 02/18] Add lootbox epoch and provider for trader joe --- .../main.go | 2 +- .../20231219091930-lootbox_add_epoch.sql | 98 +++++++++++++++++++ .../JoeFarmlandsOrCamelotKingdom/styles.css | 3 +- .../app/components/UtilityToken.tsx | 7 +- .../$network/dashboard/airdrop/index.tsx | 20 ++-- web/app.fluidity.money/app/util/provider.ts | 4 + web/surfing/src/types/provider.ts | 4 +- 7 files changed, 123 insertions(+), 15 deletions(-) create mode 100644 database/102-up-timescale/20231219091930-lootbox_add_epoch.sql diff --git a/cmd/microservice-lootbox-referral-distributor/main.go b/cmd/microservice-lootbox-referral-distributor/main.go index d960725a3..e5b5c5e21 100644 --- a/cmd/microservice-lootbox-referral-distributor/main.go +++ b/cmd/microservice-lootbox-referral-distributor/main.go @@ -64,7 +64,7 @@ func main() { Application: applications.ApplicationNone, } - go queue.SendMessage(lootboxes_queue.TopicLootboxes, referralLootbox) + queue.SendMessage(lootboxes_queue.TopicLootboxes, referralLootbox) } }) } diff --git a/database/102-up-timescale/20231219091930-lootbox_add_epoch.sql b/database/102-up-timescale/20231219091930-lootbox_add_epoch.sql new file mode 100644 index 000000000..bdcd19f95 --- /dev/null +++ b/database/102-up-timescale/20231219091930-lootbox_add_epoch.sql @@ -0,0 +1,98 @@ + +-- migrate:up + +CREATE TYPE lootbox_epoch AS ENUM ( + 'epoch_1', + 'epoch_2' +); + +ALTER TABLE lootbox + ADD COLUMN epoch lootbox_epoch NOT NULL DEFAULT 'epoch_1'; + +ALTER TABLE lootbox_referral_codes + ADD COLUMN epoch lootbox_epoch NOT NULL DEFAULT 'epoch_1'; + +ALTER TABLE lootbox_referrals + ADD COLUMN epoch lootbox_epoch NOT NULL DEFAULT 'epoch_1'; + +DROP FUNCTION lootbox_referral_lootbottle_counts; + +CREATE FUNCTION lootbox_referral_lootbottle_counts(epoch_ lootbox_epoch) +RETURNS SETOF lootbox_counts_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + address, + COALESCE(tier1, 0), + COALESCE(tier2, 0), + COALESCE(tier3, 0), + COALESCE(tier4, 0), + COALESCE(tier5, 0) +FROM crosstab( + 'SELECT + address, + reward_tier, + SUM(lootbox_count) + FROM lootbox + WHERE source=''referral'' AND epoch = epoch_ + GROUP BY + address, + reward_tier + ORDER BY 1', + 'VALUES (1),(2),(3),(4),(5)' +) AS ct( + address VARCHAR, + tier1 NUMERIC, + tier2 NUMERIC, + tier3 NUMERIC, + tier4 NUMERIC, + tier5 NUMERIC +); +$$; + +-- migrate:down + +ALTER TABLE lootbox DROP COLUMN epoch; + +ALTER TABLE lootbox_referral_codes DROP COLUMN epoch; + +ALTER TABLE lootbox_referrals DROP COLUMN epoch; + +DROP FUNCTION lootbox_referral_lootbottle_counts; + +CREATE FUNCTION lootbox_referral_lootbottle_counts() +RETURNS SETOF lootbox_counts_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + address, + COALESCE(tier1, 0), + COALESCE(tier2, 0), + COALESCE(tier3, 0), + COALESCE(tier4, 0), + COALESCE(tier5, 0) +FROM crosstab( + 'SELECT + address, + reward_tier, + SUM(lootbox_count) + FROM lootbox + WHERE source=''referral'' + GROUP BY + address, + reward_tier + ORDER BY 1', + 'VALUES (1),(2),(3),(4),(5)' +) AS ct( + address VARCHAR, + tier1 NUMERIC, + tier2 NUMERIC, + tier3 NUMERIC, + tier4 NUMERIC, + tier5 NUMERIC +); +$$; diff --git a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css index 3b8e34bf9..1cf9eb4dd 100644 --- a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css +++ b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css @@ -10,7 +10,7 @@ } .joe_farmlands_or_camelot_img_joe { - clip-path: polygon(0% 0%, 0% 100%, 100% 0%); + clip-path: polygon(0% 0%, 0% 100%, 100% 10%); } .joe_farmlands_or_camelot_img_camelot { @@ -27,6 +27,5 @@ @keyframes joe_farmlands_or_camelot_img_scale { to { transform: scale(1.025); - filter: drop-shadow(0px 0px 0px #333); } } diff --git a/web/app.fluidity.money/app/components/UtilityToken.tsx b/web/app.fluidity.money/app/components/UtilityToken.tsx index d9cee2329..b71f71e26 100644 --- a/web/app.fluidity.money/app/components/UtilityToken.tsx +++ b/web/app.fluidity.money/app/components/UtilityToken.tsx @@ -10,7 +10,12 @@ const UtilityToken = ({ utility, ...imgProps }: IUtilityToken) => { return ; case "sushi": return ; - case "trader": + case "trader_joe": + return ; + case "ramses": + return ; + case "jumper": + return ; case "arb": return ; default: diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx index a818d7528..33b8e3c5c 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx @@ -624,7 +624,7 @@ const Airdrop = () => { style={{ marginBottom: "0.5em" }} className={"no-margin"} > - Welcome to Fluidity's Airdrop Event! + Airdrop V2: Arbitrum's Space Expedition. Fluidify your assets, transact them, and boost your rewards by @@ -944,7 +944,7 @@ const Airdrop = () => { className={"no-margin"} style={{ marginBottom: "0.5em" }} > - Welcome to Fluidity's Airdrop Event! + Airdrop V2: Arbitrum's Space Expedition. Fluidify your assets, transact them, and boost your rewards @@ -1172,16 +1172,16 @@ const MultiplierTasks = () => { const [tasks, setTasks] = useState<"1x" | "6x">("6x"); const providerLinks: { provider: Provider; link: string }[] = [ - { provider: "Uniswap", link: "https://app.uniswap.org/#/swap" }, + { provider: "Jumper", link: "https://app.uniswap.org/#/swap" }, { - provider: "Sushiswap", - link: "https://www.sushi.com/swap?fromChainId=42161&fromCurrency=0x4CFA50B7Ce747e2D61724fcAc57f24B748FF2b2A&toChainId=42161&toCurrency=NATIVE&amount=", + provider: "Uniswap", + link: "https://app.uniswap.org/#/swap" }, - { provider: "Camelot", link: "https://app.camelot.exchange/" }, - { provider: "Saddle", link: "https://saddle.exchange/#/" }, - { provider: "Chronos", link: "https://app.chronos.exchange/" }, + { provider: "Trader Joe", link: "https://app.camelot.exchange/" }, + { provider: "Camelot", link: "https://saddle.exchange/#/" }, + { provider: "Sushiswap", link: "https://app.chronos.exchange/" }, { - provider: "Kyber", + provider: "Ramses", link: "https://kyberswap.com/swap/arbitrum/fusdc-to-usdc", }, ]; @@ -1193,7 +1193,7 @@ const MultiplierTasks = () => { Multiplier Tasks - Perform displayed tasks to earn the respective multipliers. + Transact fUSDC on listed platforms to earn more!
{ return "Lifinity"; case "mercurial": return "Mercurial"; + case "ramses": + return "Ramses"; case "trader_joe": return "Trader Joe"; + case "jumper": + return "Jumper"; case "fluidity": case "spl": case "none": diff --git a/web/surfing/src/types/provider.ts b/web/surfing/src/types/provider.ts index ca3d5d757..d1a15e14f 100644 --- a/web/surfing/src/types/provider.ts +++ b/web/surfing/src/types/provider.ts @@ -29,4 +29,6 @@ export type Provider = | "Sushiswap" | "Trader Joe" | "Uniswap" - | "XY Finance"; + | "XY Finance" + | "Ramses" + | "Jumper"; From c027d5fe4d4f04d2f63680aff4d8c8bb011a0a0f Mon Sep 17 00:00:00 2001 From: user Date: Tue, 19 Dec 2023 15:13:18 +1030 Subject: [PATCH 03/18] Add a current epoch system to lootboxes --- .../main.go | 48 +++- .../main.go | 6 +- .../main.go | 5 +- .../main.go | 40 ++- .../README.md | 6 +- .../main.go | 20 +- common/ethereum/applications/applications.go | 7 + .../20231219091930-lootbox_add_epoch.sql | 3 +- ...19094456-lootbox_config_add_prev_epoch.sql | 35 +++ lib/databases/timescale/lootboxes/config.go | 101 +++++++ .../timescale/lootboxes/lootboxes.go | 28 +- lib/databases/timescale/lootboxes/rewards.go | 110 ++++---- .../timescale/lootboxes/rewards_test.go | 256 +++++++++--------- lib/queues/lootboxes/lootboxes.go | 8 +- lib/types/lootboxes/lootboxes.go | 3 + 15 files changed, 464 insertions(+), 212 deletions(-) create mode 100644 database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql create mode 100644 lib/databases/timescale/lootboxes/config.go diff --git a/cmd/microservice-ethereum-create-transaction-lootboxes/main.go b/cmd/microservice-ethereum-create-transaction-lootboxes/main.go index fb1973511..05fc31a5c 100644 --- a/cmd/microservice-ethereum-create-transaction-lootboxes/main.go +++ b/cmd/microservice-ethereum-create-transaction-lootboxes/main.go @@ -10,11 +10,6 @@ import ( "math/big" "time" - "github.com/ethereum/go-ethereum/accounts/abi/bind" - "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" - libEthereum "github.com/fluidity-money/fluidity-app/common/ethereum" - ethereumApps "github.com/fluidity-money/fluidity-app/common/ethereum/applications" database "github.com/fluidity-money/fluidity-app/lib/databases/timescale/lootboxes" user_actions "github.com/fluidity-money/fluidity-app/lib/databases/timescale/user-actions" "github.com/fluidity-money/fluidity-app/lib/log" @@ -27,12 +22,20 @@ import ( "github.com/fluidity-money/fluidity-app/lib/types/misc" "github.com/fluidity-money/fluidity-app/lib/types/worker" "github.com/fluidity-money/fluidity-app/lib/util" + + libEthereum "github.com/fluidity-money/fluidity-app/common/ethereum" + ethereumApps "github.com/fluidity-money/fluidity-app/common/ethereum/applications" + + "github.com/ethereum/go-ethereum/accounts/abi/bind" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" ) const ( // EnvTokensList to relate the received token names to a contract address // of the form ADDR1:TOKEN1:DECIMALS1,ADDR2:TOKEN2:DECIMALS2,... EnvTokensList = "FLU_ETHEREUM_TOKENS_LIST" + // EnvGethHttpUrl to use when performing RPC requests EnvGethHttpUrl = `FLU_ETHEREUM_HTTP_URL` ) @@ -85,6 +88,26 @@ func main() { tokenShortName = tokenDetails.TokenShortName ) + programFound, hasBegun, currentEpoch, _ := database.GetLootboxConfig() + + if !programFound { + log.App(func(k *log.Log) { + k.Message = "No lootbox epoch found, ignoring a request to track winners!" + }) + + return + } + + if hasBegun { + log.Fatal(func(k *log.Log) { + k.Message = "Lootbox epoch that was found is not running! Ignoring a request to track!" + }) + + return + } + + log.Debugf("Lootbox current epoch running is %v!", currentEpoch) + // don't track fluidification if winner.RewardType != "send" { log.Debug(func(k *log.Log) { @@ -114,7 +137,11 @@ func main() { // fetch parameters to call GetApplicationFee // wait for transaction to be mined before fetching receipt - transaction, isPending, err := ethClient.TransactionByHash(context.Background(), common.HexToHash(transactionHash)) + + transaction, isPending, err := ethClient.TransactionByHash( + context.Background(), + common.HexToHash(transactionHash), + ) if err != nil { log.Fatal(func(k *log.Log) { @@ -172,7 +199,14 @@ func main() { inputData := transaction.Data() - feeData, _, _, err := ethereumApps.GetApplicationFee(applicationTransfer, ethClient, fluidTokenContract, tokenDecimals, receipt, inputData) + feeData, _, _, err := ethereumApps.GetApplicationFee( + applicationTransfer, + ethClient, + fluidTokenContract, + tokenDecimals, + receipt, + inputData, + ) if err != nil { log.Fatal(func(k *log.Log) { diff --git a/cmd/microservice-lootbox-referral-activator/main.go b/cmd/microservice-lootbox-referral-activator/main.go index a065abc4b..5b0c5dd28 100644 --- a/cmd/microservice-lootbox-referral-activator/main.go +++ b/cmd/microservice-lootbox-referral-activator/main.go @@ -26,9 +26,7 @@ const ( ) func main() { - var ( - lootboxReferralAmount_ = util.GetEnvOrFatal(EnvLootboxReferralAmount) - ) + lootboxReferralAmount_ := util.GetEnvOrFatal(EnvLootboxReferralAmount) lootboxReferralAmount, err := strconv.ParseUint(lootboxReferralAmount_, 10, 64) @@ -45,6 +43,7 @@ func main() { transactionHash = lootbox.TransactionHash address = lootbox.Address lootboxCount = lootbox.LootboxCount + epoch = lootbox.Epoch ) // don't track non-transaction lootboxes @@ -102,6 +101,7 @@ func main() { RewardTier: 1, LootboxCount: 5, Application: applications.ApplicationNone, + Epoch: epoch, } queue.SendMessage(lootboxes_queue.TopicLootboxes, referralLootbox) diff --git a/cmd/microservice-lootbox-referral-distributor/main.go b/cmd/microservice-lootbox-referral-distributor/main.go index e5b5c5e21..80abdecd8 100644 --- a/cmd/microservice-lootbox-referral-distributor/main.go +++ b/cmd/microservice-lootbox-referral-distributor/main.go @@ -5,7 +5,6 @@ package main import ( - "github.com/fluidity-money/fluidity-app/common/ethereum/applications" "github.com/fluidity-money/fluidity-app/lib/databases/timescale/referrals" "github.com/fluidity-money/fluidity-app/lib/log" "github.com/fluidity-money/fluidity-app/lib/queue" @@ -13,6 +12,8 @@ import ( "github.com/fluidity-money/fluidity-app/lib/types/ethereum" "github.com/fluidity-money/fluidity-app/lib/types/lootboxes" "github.com/fluidity-money/fluidity-app/lib/types/misc" + + "github.com/fluidity-money/fluidity-app/common/ethereum/applications" ) func main() { @@ -23,6 +24,7 @@ func main() { address = lootbox.Address lootboxCount = lootbox.LootboxCount awardedTime = lootbox.AwardedTime + epoch = lootbox.Epoch ) // don't track non-transaction lootboxes @@ -62,6 +64,7 @@ func main() { RewardTier: 1, LootboxCount: referralLootboxCount, Application: applications.ApplicationNone, + Epoch: epoch, } queue.SendMessage(lootboxes_queue.TopicLootboxes, referralLootbox) diff --git a/cmd/microservice-lootbox-reward-top-winners/main.go b/cmd/microservice-lootbox-reward-top-winners/main.go index 12119feeb..35d831bcc 100644 --- a/cmd/microservice-lootbox-reward-top-winners/main.go +++ b/cmd/microservice-lootbox-reward-top-winners/main.go @@ -32,8 +32,44 @@ func main() { // endTime is the beginning of the day after startTime (the start of the current date) endTime := currentTime - // fetch and log the top 10 users - topUsers := lootboxes.GetTopApplicationUsersByLootboxCount(startTime, endTime, applications.ApplicationKyberClassic) + programFound, hasBegun, currentEpoch, currentApplication := lootboxes.GetLootboxConfig() + + if !programFound { + log.App(func(k *log.Log) { + k.Message = "No lootbox epoch found! Skipping running." + }) + + return + } + + if !hasBegun { + log.App(func(k *log.Log) { + k.Message = "Current lootbox epoch has not yet started! Skipping running." + }) + + return + } + + var topUsers []lootboxes.UserLootboxCount + + // if there's a current application focus, then we want to reward only specific winners + + if currentApplication != application.ApplicationNone { + // fetch and log the top 10 users for a specific application + topUsers = lootboxes.GetTopApplicationUsersByLootboxCount( + startTime, + endTime, + currentApplication, + currentEpoch, + ) + } else { + topUsers = lootboxes.GetTopUsersByLootboxCount( + startTime, + endTime, + currentEpoch, + ) + } + for i, user := range topUsers { log.App(func(k *log.Log) { k.Format( diff --git a/cmd/microservice-redeem-testnet-lootboxes/README.md b/cmd/microservice-redeem-testnet-lootboxes/README.md index 988ac37b6..8c9a2f45b 100644 --- a/cmd/microservice-redeem-testnet-lootboxes/README.md +++ b/cmd/microservice-redeem-testnet-lootboxes/README.md @@ -1,7 +1,11 @@ # microservice-redeem-testnet-lootboxes -Watch for events indicating ownership of a testnet address and reward the owner. +Watch for events indicating ownership of a testnet address and reward +the owner. + +If an epoch is not currently running, then this should break as +someone is using the contract improperly. ## Environment variables diff --git a/cmd/microservice-redeem-testnet-lootboxes/main.go b/cmd/microservice-redeem-testnet-lootboxes/main.go index 9ddf11e58..7d5b7e997 100644 --- a/cmd/microservice-redeem-testnet-lootboxes/main.go +++ b/cmd/microservice-redeem-testnet-lootboxes/main.go @@ -34,6 +34,24 @@ func main() { ) logs.Logs(func(l logs.Log) { + // if a user encounters this, how did they get here? + + programFound, hasBegun, currentEpoch, _ := lootboxes.GetLootboxConfig() + + if !programFound { + log.Fatal(func(k *log.Log) { + k.Message = "No lootbox program found, but a log was received for a testnet redemption!" + }) + } + + if hasBegun { + log.Fatal(func(k *log.Log) { + k.Message = "Lootbox program that was found is not running!" + }) + } + + log.Debugf("Lootbox current epoch running is %v!", currentEpoch) + if l.Address != addressConfirmerContractAddress { log.Debug(func(k *log.Log) { k.Format( @@ -123,7 +141,7 @@ func main() { } for _, lootbox := range boxes { - lootboxes.InsertLootbox(lootbox) + lootboxes.InsertLootbox(lootbox, currentEpoch) } }) } diff --git a/common/ethereum/applications/applications.go b/common/ethereum/applications/applications.go index fac0e3ec9..9e4349fdc 100644 --- a/common/ethereum/applications/applications.go +++ b/common/ethereum/applications/applications.go @@ -39,6 +39,8 @@ import ( "github.com/ethereum/go-ethereum/ethclient" ) +type Application = libApps.Application + const ( // ApplicationNone is the nil value representing a transfer. ApplicationNone libApps.Application = iota @@ -66,6 +68,11 @@ const ( ApplicationTraderJoe ) +// ParseApplicationName shadows the lib types definition +func ParseApplicationName(name string) (Application, error) { + return libApps.ParseApplicationName(name) +} + // GetApplicationFee to find the fee (in USD) paid by a user for the application interaction // returns (feeData wiht Fee set to nil, ni) in the case where the application event is legitimate, but doesn't involve // the fluid asset we're tracking, e.g. in a multi-token pool where two other tokens are swapped diff --git a/database/102-up-timescale/20231219091930-lootbox_add_epoch.sql b/database/102-up-timescale/20231219091930-lootbox_add_epoch.sql index bdcd19f95..df28fe5e4 100644 --- a/database/102-up-timescale/20231219091930-lootbox_add_epoch.sql +++ b/database/102-up-timescale/20231219091930-lootbox_add_epoch.sql @@ -3,7 +3,8 @@ CREATE TYPE lootbox_epoch AS ENUM ( 'epoch_1', - 'epoch_2' + 'epoch_2', + 'epoch_testing' ); ALTER TABLE lootbox diff --git a/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql b/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql new file mode 100644 index 000000000..9e7eca0b7 --- /dev/null +++ b/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql @@ -0,0 +1,35 @@ + +-- migrate:up + +CREATE TABLE lootbox_config ( + -- is_current_program if enabled, it's assumed that this is + -- the current epoch routine, and config is derived from this + is_current_program BOOLEAN NOT NULL DEFAULT FALSE, + + -- program_begin_date to begin counting lootbottles from + -- this date onwards, in UTC + program_begin TIMESTAMP, + + -- program_end to use as the final date for the epoch, and + -- when to stop counting (also in UTC) + program_end TIMESTAMP, + + -- epoch_identifier to use as the identifier for the epoch with + -- the enum + epoch_identifier lootbox_epoch NOT NULL, + + -- ethereum_application that should the current focus of the lootbox + -- mini leaderboard competitions + ethereum_application ethereum_application NOT NULL DEFAULT 'none' +); + +INSERT INTO lootbox_config VALUES ( + FALSE, + '2023-05-01 12:00:00+02', + '2023-06-28 12:00:00+02', + 'epoch_1' +); + +-- migrate:down + +DROP TABLE lootbox_config; diff --git a/lib/databases/timescale/lootboxes/config.go b/lib/databases/timescale/lootboxes/config.go new file mode 100644 index 000000000..5f8e1f12e --- /dev/null +++ b/lib/databases/timescale/lootboxes/config.go @@ -0,0 +1,101 @@ +// Copyright 2023 Fluidity Money. All rights reserved. Use of this +// source code is governed by a GPL-style license that can be found in the +// LICENSE.md file. + +package lootboxes + +import ( + "database/sql" + "fmt" + + "github.com/fluidity-money/fluidity-app/common/ethereum/applications" + "github.com/fluidity-money/fluidity-app/lib/log" + "github.com/fluidity-money/fluidity-app/lib/timescale" +) + +const ( + Epoch1 = "epoch_1" + Epoch2 = "epoch_2" + EpochTesting = "epoch_testing" +) + +// GetConfig that's currently marked as enabled, also getting whether the +// program has currently begun or not. Fatals if the number of rows returned +// exceeds 1. +func GetLootboxConfig() (programFound bool, hasBegun bool, curEpoch string, curApplication applications.Application) { + timescaleClient := timescale.Client() + + statementText := fmt.Sprintf( + `WITH t AS ( + SELECT CURRENT_TIMESTAMP AT TIME ZONE 'UTC' AS timestamp + ) + SELECT + program_begin < (select timestamp from t) AND + program_end > (select timestamp from t), + epoch_identifier, + current_application + FROM %s + WHERE is_current_program;`, + + TableLootboxConfig, + ) + + rows, err := timescaleClient.Query(statementText) + + switch err { + case sql.ErrNoRows: + return false, false, "", applications.ApplicationNone + + case nil: + // do nothing + + default: + log.Fatal(func(k *log.Log) { + k.Context = Context + k.Message = "Failed to query for lootbox config!" + k.Payload = err + }) + } + + defer rows.Close() + + if !rows.Next() { + return false, false, "", applications.ApplicationNone + } + + var applicationString string + + err = rows.Scan(&hasBegun, &curEpoch, &applicationString) + + if err != nil { + log.Fatal(func(k *log.Log) { + k.Context = Context + k.Message = "Failed to query for lootbox config!" + k.Payload = err + }) + } + + curApplication, err = applications.ParseApplicationName(applicationString) + + if err != nil { + log.Fatal(func(k *log.Log) { + k.Context = Context + + k.Format( + "Failed to parse the Ethereum application name %#v!", + applicationString, + ) + + k.Payload = err + }) + } + + if rows.Next() { + log.Fatal(func(k *log.Log) { + k.Context = Context + k.Message = "Duplicate enabled row for the lootbox_config found!" + }) + } + + return true, hasBegun, curEpoch, curApplication +} diff --git a/lib/databases/timescale/lootboxes/lootboxes.go b/lib/databases/timescale/lootboxes/lootboxes.go index 471c89e20..846399f89 100644 --- a/lib/databases/timescale/lootboxes/lootboxes.go +++ b/lib/databases/timescale/lootboxes/lootboxes.go @@ -1,3 +1,7 @@ +// Copyright 2023 Fluidity Money. All rights reserved. Use of this +// source code is governed by a GPL-style license that can be found in the +// LICENSE.md file. + package lootboxes import ( @@ -17,12 +21,16 @@ const ( // TableLootboxes to use when inserting // derived lootboxes to database TableLootboxes = `lootbox` + + // TableLootboxConfig to use for setting configuration + // for the currently running epoch + TableLootboxConfig = `lootbox_config` ) type Lootbox = types.Lootbox // InsertLootbox inserts a Lootbox into the database -func InsertLootbox(lootbox Lootbox) { +func InsertLootbox(lootbox Lootbox, currentEpoch string) { timescaleClient := timescale.Client() statementText := fmt.Sprintf( @@ -34,7 +42,8 @@ func InsertLootbox(lootbox Lootbox) { volume, reward_tier, lootbox_count, - application + application, + epoch ) VALUES ( @@ -45,7 +54,8 @@ func InsertLootbox(lootbox Lootbox) { $5, $6, $7, - $8 + $8, + $9 )`, TableLootboxes, @@ -61,6 +71,7 @@ func InsertLootbox(lootbox Lootbox) { lootbox.RewardTier, lootbox.LootboxCount, lootbox.Application.String(), + lootbox.Epoch, ) if err != nil { @@ -73,7 +84,7 @@ func InsertLootbox(lootbox Lootbox) { } // GetLootboxes gets all Lootboxes earned by address, limited by a number -func GetLootboxes(address ethereum.Address, limit int) []Lootbox { +func GetLootboxes(address ethereum.Address, currentEpoch string, limit int) []Lootbox { timescaleClient := timescale.Client() statementText := fmt.Sprintf( @@ -87,9 +98,9 @@ func GetLootboxes(address ethereum.Address, limit int) []Lootbox { lootbox_count, application - FROM %s - WHERE address = $1 - LIMIT $2 + FROM %s + WHERE address = $1 AND epoch = $2 + LIMIT $3 `, TableLootboxes, @@ -98,6 +109,7 @@ func GetLootboxes(address ethereum.Address, limit int) []Lootbox { rows, err := timescaleClient.Query( statementText, address, + currentEpoch, limit, ) @@ -143,6 +155,8 @@ func GetLootboxes(address ethereum.Address, limit int) []Lootbox { }) } + lootbox.Epoch = currentEpoch + application, err := applications.ParseApplicationName(application_) if err != nil { diff --git a/lib/databases/timescale/lootboxes/rewards.go b/lib/databases/timescale/lootboxes/rewards.go index 430b7abd4..00ae8b518 100644 --- a/lib/databases/timescale/lootboxes/rewards.go +++ b/lib/databases/timescale/lootboxes/rewards.go @@ -24,7 +24,7 @@ type UserLootboxCount struct { } // buildUserRewardValuesString to build a variadic string for the values to insert for top winners -func buildUserRewardValuesString(userCount int) (string, error) { +func buildUserRewardValuesString(currentEpoch string, userCount int) (string, error) { if userCount < 1 || userCount > 10 { return "", fmt.Errorf( "invalid number of leaderboard users - want 1-10, got %d", @@ -33,32 +33,32 @@ func buildUserRewardValuesString(userCount int) (string, error) { } rewardStrings := []string{ - `($2, '', 'leaderboard_prize', $1, 0, 1, 30, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 2, 10, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 3, 5, 'none')`, + `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2)`, - `($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 2, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 3, 2, 'none')`, + `($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 2, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 3, 2, 'none', $2)`, - `($4, '', 'leaderboard_prize', $1, 0, 1, 15, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 2, 3, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 3, 1, 'none')`, + `($4, '', 'leaderboard_prize', $1, 0, 1, 15, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 2, 3, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 3, 1, 'none', $2)`, - `($5, '', 'leaderboard_prize', $1, 0, 1, 12, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 2, 1, 'none')`, + `($6, '', 'leaderboard_prize', $1, 0, 1, 12, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 2, 1, 'none', $2)`, - "($6, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')", + "($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)", - "($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')", + "($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)", - "($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')", + "($9, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)", - "($9, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')", + "($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)", - "($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')", + "($11, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)", - "($11, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')", + "($12, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)", } var output strings.Builder @@ -100,8 +100,8 @@ func buildUserRewardValuesString(userCount int) (string, error) { // InsertTopUserReward to insert lootboxes for the given users for their activity during the airdrop. // Expects 10 users to reward -func InsertTopUserReward(currentTime time.Time, users []UserLootboxCount) { - valuesString, err := buildUserRewardValuesString(len(users)) +func InsertTopUserReward(currentEpoch string, currentTime time.Time, users []UserLootboxCount) { + valuesString, err := buildUserRewardValuesString(currentEpoch, len(users)) if err != nil { log.Fatal(func(k *log.Log) { @@ -114,14 +114,15 @@ func InsertTopUserReward(currentTime time.Time, users []UserLootboxCount) { statementText := fmt.Sprintf( `INSERT INTO %s ( - address, - transaction_hash, - source, - awarded_time, - volume, - reward_tier, - lootbox_count, - application + address, + transaction_hash, + source, + awarded_time, + volume, + reward_tier, + lootbox_count, + application, + epoch ) VALUES %s`, TableLootboxes, @@ -129,8 +130,7 @@ func InsertTopUserReward(currentTime time.Time, users []UserLootboxCount) { ) // build variadic arguments [time, users...] - var args []interface{} - args = append(args, currentTime) + args := []interface{}{currentTime, currentEpoch} for _, user := range users { args = append(args, user.Address) @@ -151,21 +151,22 @@ func InsertTopUserReward(currentTime time.Time, users []UserLootboxCount) { } // fetch the 10 addresses with the highest lootboxes earned during the given period -func GetTopUsersByLootboxCount(startTime, endTime time.Time) []UserLootboxCount { +func GetTopUsersByLootboxCount(currentEpoch string, startTime, endTime time.Time) []UserLootboxCount { timescaleClient := timescale.Client() statementText := fmt.Sprintf( - `SELECT - address, - SUM(lootbox_count) AS lootbox_count + `SELECT + address, + SUM(lootbox_count) AS lootbox_count FROM %s - WHERE + WHERE awarded_time >= $1 AT TIME ZONE $3 AND - awarded_time < $2 AT TIME ZONE $4 AND - source != 'leaderboard_prize' - GROUP BY address + awarded_time < $2 AT TIME ZONE $4 AND + source != 'leaderboard_prize' AND + epoch = $5 + GROUP BY address ORDER BY lootbox_count DESC - LIMIT $5`, + LIMIT $6`, TableLootboxes, ) @@ -176,6 +177,7 @@ func GetTopUsersByLootboxCount(startTime, endTime time.Time) []UserLootboxCount endTime, LootboxRewardTimezone, LootboxRewardTimezone, + currentEpoch, 10, ) @@ -193,10 +195,8 @@ func GetTopUsersByLootboxCount(startTime, endTime time.Time) []UserLootboxCount for rows.Next() { var user UserLootboxCount - err := rows.Scan( - &user.Address, - &user.LootboxCount, - ) + + err := rows.Scan(&user.Address, &user.LootboxCount) if err != nil { log.Fatal(func(k *log.Log) { @@ -215,20 +215,21 @@ func GetTopUsersByLootboxCount(startTime, endTime time.Time) []UserLootboxCount const LootboxRewardTimezone = "Australia/Adelaide" // fetch the 10 addresses with the highest lootboxes earned during the given period on the given application -func GetTopApplicationUsersByLootboxCount(startTime, endTime time.Time, application applications.Application) []UserLootboxCount { +func GetTopApplicationUsersByLootboxCount(currentEpoch string, startTime, endTime time.Time, application applications.Application) []UserLootboxCount { timescaleClient := timescale.Client() statementText := fmt.Sprintf( - `SELECT - address, - SUM(lootbox_count) AS lootbox_count + `SELECT + address, + SUM(lootbox_count) AS lootbox_count FROM %s - WHERE + WHERE awarded_time >= $1 AT TIME ZONE $3 AND - awarded_time < $2 AT TIME ZONE $4 AND + awarded_time < $2 AT TIME ZONE $4 AND source != 'leaderboard_prize' AND - application = $6 - GROUP BY address + application = $6 AND + epoch = $7 + GROUP BY address ORDER BY lootbox_count DESC LIMIT $5`, @@ -243,6 +244,7 @@ func GetTopApplicationUsersByLootboxCount(startTime, endTime time.Time, applicat LootboxRewardTimezone, 10, application.String(), + currentEpoch, ) if err != nil { @@ -259,10 +261,8 @@ func GetTopApplicationUsersByLootboxCount(startTime, endTime time.Time, applicat for rows.Next() { var user UserLootboxCount - err := rows.Scan( - &user.Address, - &user.LootboxCount, - ) + + err := rows.Scan(&user.Address, &user.LootboxCount) if err != nil { log.Fatal(func(k *log.Log) { diff --git a/lib/databases/timescale/lootboxes/rewards_test.go b/lib/databases/timescale/lootboxes/rewards_test.go index 7a74779d2..06e3cfa09 100644 --- a/lib/databases/timescale/lootboxes/rewards_test.go +++ b/lib/databases/timescale/lootboxes/rewards_test.go @@ -9,146 +9,146 @@ import ( func TestBuildUserRewardValuesString(t *testing.T) { expectedRewardStrings := []string{ - `($2, '', 'leaderboard_prize', $1, 0, 1, 30, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 2, 10, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 3, 5, 'none')`, - - `($2, '', 'leaderboard_prize', $1, 0, 1, 30, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 2, 10, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 3, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 2, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 3, 2, 'none')`, - - `($2, '', 'leaderboard_prize', $1, 0, 1, 30, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 2, 10, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 3, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 2, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 3, 2, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 1, 15, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 2, 3, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 3, 1, 'none')`, - - `($2, '', 'leaderboard_prize', $1, 0, 1, 30, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 2, 10, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 3, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 2, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 3, 2, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 1, 15, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 2, 3, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 3, 1, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 1, 12, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 2, 1, 'none')`, - - `($2, '', 'leaderboard_prize', $1, 0, 1, 30, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 2, 10, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 3, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 2, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 3, 2, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 1, 15, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 2, 3, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 3, 1, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 1, 12, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 2, 1, 'none'), -($6, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')`, - - `($2, '', 'leaderboard_prize', $1, 0, 1, 30, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 2, 10, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 3, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 2, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 3, 2, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 1, 15, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 2, 3, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 3, 1, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 1, 12, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 2, 1, 'none'), -($6, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')`, - - `($2, '', 'leaderboard_prize', $1, 0, 1, 30, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 2, 10, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 3, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 2, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 3, 2, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 1, 15, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 2, 3, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 3, 1, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 1, 12, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 2, 1, 'none'), -($6, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')`, - - `($2, '', 'leaderboard_prize', $1, 0, 1, 30, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 2, 10, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 3, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 2, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 3, 2, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 1, 15, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 2, 3, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 3, 1, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 1, 12, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 2, 1, 'none'), -($6, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($9, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')`, - - `($2, '', 'leaderboard_prize', $1, 0, 1, 30, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 2, 10, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 3, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 2, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 3, 2, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 1, 15, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 2, 3, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 3, 1, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 1, 12, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 2, 1, 'none'), -($6, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($9, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')`, - - `($2, '', 'leaderboard_prize', $1, 0, 1, 30, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 2, 10, 'none'), -($2, '', 'leaderboard_prize', $1, 0, 3, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 2, 5, 'none'), -($3, '', 'leaderboard_prize', $1, 0, 3, 2, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 1, 15, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 2, 3, 'none'), -($4, '', 'leaderboard_prize', $1, 0, 3, 1, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 1, 12, 'none'), -($5, '', 'leaderboard_prize', $1, 0, 2, 1, 'none'), -($6, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($9, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none'), -($11, '', 'leaderboard_prize', $1, 0, 1, 10, 'none')`, + `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2)`, + + `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 2, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 3, 2, 'none', $2)`, + + `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 2, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 3, 2, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 1, 15, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 2, 3, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 3, 1, 'none', $2)`, + + `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 2, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 3, 2, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 1, 15, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 2, 3, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 3, 1, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 1, 12, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 2, 1, 'none', $2)`, + + `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 2, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 3, 2, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 1, 15, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 2, 3, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 3, 1, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 1, 12, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 2, 1, 'none', $2), +($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)`, + + `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 2, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 3, 2, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 1, 15, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 2, 3, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 3, 1, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 1, 12, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 2, 1, 'none', $2), +($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)`, + + `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 2, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 3, 2, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 1, 15, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 2, 3, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 3, 1, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 1, 12, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 2, 1, 'none', $2), +($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($9, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)`, + + `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 2, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 3, 2, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 1, 15, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 2, 3, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 3, 1, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 1, 12, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 2, 1, 'none', $2), +($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($9, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)`, + + `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 2, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 3, 2, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 1, 15, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 2, 3, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 3, 1, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 1, 12, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 2, 1, 'none', $2), +($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($9, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)`, + + `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), +($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 2, 5, 'none', $2), +($4, '', 'leaderboard_prize', $1, 0, 3, 2, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 1, 15, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 2, 3, 'none', $2), +($5, '', 'leaderboard_prize', $1, 0, 3, 1, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 1, 12, 'none', $2), +($6, '', 'leaderboard_prize', $1, 0, 2, 1, 'none', $2), +($7, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($9, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($11, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)`, } for i, expectedString := range expectedRewardStrings { userCount := i + 1 - rewardString, err := buildUserRewardValuesString(userCount) + rewardString, err := buildUserRewardValuesString("epoch_1", userCount) require.NoError(t, err) assert.Equal(t, expectedString, rewardString) } - rewardString, err := buildUserRewardValuesString(0) + rewardString, err := buildUserRewardValuesString("epoch_1", 0) assert.Empty(t, rewardString) assert.Error(t, err) - rewardString, err = buildUserRewardValuesString(11) + rewardString, err = buildUserRewardValuesString("epoch_1", 11) assert.Empty(t, rewardString) assert.Error(t, err) } diff --git a/lib/queues/lootboxes/lootboxes.go b/lib/queues/lootboxes/lootboxes.go index a0a886737..a6ec6d3aa 100644 --- a/lib/queues/lootboxes/lootboxes.go +++ b/lib/queues/lootboxes/lootboxes.go @@ -12,13 +12,9 @@ import ( types "github.com/fluidity-money/fluidity-app/lib/types/lootboxes" ) -const ( - TopicLootboxes = `lootboxes` -) +const TopicLootboxes = `lootboxes` -type ( - Lootbox = types.Lootbox -) +type Lootbox = types.Lootbox func LootboxesAll(f func(Lootbox)) { queue.GetMessages(TopicLootboxes, func(message queue.Message) { diff --git a/lib/types/lootboxes/lootboxes.go b/lib/types/lootboxes/lootboxes.go index 0b2998262..d13522184 100644 --- a/lib/types/lootboxes/lootboxes.go +++ b/lib/types/lootboxes/lootboxes.go @@ -38,4 +38,7 @@ type Lootbox struct { // Application is the application involved in the source transfer Application applications.Application `json:"application"` + + // Epoch of the lootbox program thats taking place + Epoch string `json:"epoch"` } From bc8ad01edd250dbe48a7df436a2c9d4ee02a13b9 Mon Sep 17 00:00:00 2001 From: user Date: Wed, 3 Jan 2024 10:43:44 +1030 Subject: [PATCH 04/18] Add amount earned left join, queries to the frontend, extra features to cmd --- .../main.go | 23 +---- .../README.md | 3 + .../main.go | 4 +- .../processing.go | 83 +++++++++++++++-- common/ethereum/applications/jumper/init.go | 27 ++++++ common/ethereum/applications/jumper/jumper.go | 15 ++++ .../20230323164105-airdrop_leaderboard.sql | 18 ++-- ...rop_leaderboard_add_24_hrs_application.sql | 18 ++-- ...19094456-lootbox_config_add_prev_epoch.sql | 12 ++- ...28172908-lootbox_amounts_earned_create.sql | 31 +++++++ ...320-airdrop_leaderboard_remove_chronos.sql | 31 +++++++ ...board_24_hours_add_epoch_and_arb_fusdc.sql | 89 +++++++++++++++++++ ...eaderboard_add_epoch_to_24_hours_query.sql | 79 ++++++++++++++++ .../timescale/lootboxes/lootboxes.go | 4 + lib/databases/timescale/lootboxes/rewards.go | 52 +++++++++++ .../JoeFarmlandsOrCamelotKingdom/styles.css | 7 +- web/app.fluidity.money/app/queries/index.ts | 1 + .../app/queries/useAirdropLeaderboard.ts | 31 +++++-- .../app/queries/useLootboxConfig.ts | 41 +++++++++ .../$network/dashboard/airdrop/common.tsx | 2 +- .../$network/dashboard/airdrop/index.tsx | 81 ++++++++++++----- .../routes/$network/query/lootboxConfig.tsx | 51 +++++++++++ .../contexts/LootboxProvider.tsx | 22 +++++ .../public/images/epoch2AirdropBanner.png | 4 +- .../public/images/hero/common.png | 4 +- .../public/images/hero/legendary.png | 4 +- .../public/images/hero/rare.png | 4 +- .../public/images/hero/ultra_rare.png | 4 +- .../public/images/hero/uncommon.png | 4 +- .../src/util/liquidityProviders/providers.ts | 2 + 30 files changed, 659 insertions(+), 92 deletions(-) create mode 100644 common/ethereum/applications/jumper/init.go create mode 100644 common/ethereum/applications/jumper/jumper.go create mode 100644 database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql create mode 100644 database/102-up-timescale/20240102213320-airdrop_leaderboard_remove_chronos.sql create mode 100644 database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql create mode 100644 database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_to_24_hours_query.sql create mode 100644 web/app.fluidity.money/app/queries/useLootboxConfig.ts create mode 100644 web/app.fluidity.money/app/routes/$network/query/lootboxConfig.tsx create mode 100644 web/app.fluidity.money/contexts/LootboxProvider.tsx diff --git a/cmd/microservice-ethereum-create-transaction-lootboxes/main.go b/cmd/microservice-ethereum-create-transaction-lootboxes/main.go index 05fc31a5c..b3fb5a3d0 100644 --- a/cmd/microservice-ethereum-create-transaction-lootboxes/main.go +++ b/cmd/microservice-ethereum-create-transaction-lootboxes/main.go @@ -16,7 +16,6 @@ import ( "github.com/fluidity-money/fluidity-app/lib/queue" lootboxes_queue "github.com/fluidity-money/fluidity-app/lib/queues/lootboxes" winners_queue "github.com/fluidity-money/fluidity-app/lib/queues/winners" - "github.com/fluidity-money/fluidity-app/lib/types/applications" "github.com/fluidity-money/fluidity-app/lib/types/ethereum" "github.com/fluidity-money/fluidity-app/lib/types/lootboxes" "github.com/fluidity-money/fluidity-app/lib/types/misc" @@ -24,7 +23,7 @@ import ( "github.com/fluidity-money/fluidity-app/lib/util" libEthereum "github.com/fluidity-money/fluidity-app/common/ethereum" - ethereumApps "github.com/fluidity-money/fluidity-app/common/ethereum/applications" + "github.com/fluidity-money/fluidity-app/common/ethereum/applications" "github.com/ethereum/go-ethereum/accounts/abi/bind" "github.com/ethereum/go-ethereum/common" @@ -199,7 +198,7 @@ func main() { inputData := transaction.Data() - feeData, _, _, err := ethereumApps.GetApplicationFee( + feeData, _, _, err := applications.GetApplicationFee( applicationTransfer, ethClient, fluidTokenContract, @@ -322,22 +321,8 @@ func volumeLiquidityMultiplier(volume *big.Rat, tokenDecimals int, address strin } func protocolMultiplier(application applications.Application) *big.Rat { - switch application.String() { - case "uniswap_v2": - fallthrough - case "uniswap_v3": - fallthrough - case "saddle": - fallthrough - case "curve": - fallthrough - case "camelot": - fallthrough - case "chronos": - fallthrough - case "kyber_classic": - fallthrough - case "sushiswap": + switch application { + case applications.ApplicationJumper, applications.ApplicationUniswapV3, applications.ApplicationTraderJoe, applications.ApplicationCamelot, applications.ApplicationSushiswap, applications.ApplicationRamses: return big.NewRat(2, 100) } diff --git a/cmd/microservice-ethereum-track-winners/README.md b/cmd/microservice-ethereum-track-winners/README.md index f39476d27..3ff8ba720 100644 --- a/cmd/microservice-ethereum-track-winners/README.md +++ b/cmd/microservice-ethereum-track-winners/README.md @@ -4,6 +4,9 @@ Take a list of contracts to watch and report when one of them generates a `Reward` event. +Tracks the amounts earned in the database, after scanning the current +airdrop epoch, if any. + ## Environment variables | Name | Description diff --git a/cmd/microservice-ethereum-track-winners/main.go b/cmd/microservice-ethereum-track-winners/main.go index 0bf358ce0..302042be9 100644 --- a/cmd/microservice-ethereum-track-winners/main.go +++ b/cmd/microservice-ethereum-track-winners/main.go @@ -11,13 +11,14 @@ import ( "strconv" "strings" - "github.com/fluidity-money/fluidity-app/common/ethereum/fluidity" logging "github.com/fluidity-money/fluidity-app/lib/log" "github.com/fluidity-money/fluidity-app/lib/queues/ethereum" "github.com/fluidity-money/fluidity-app/lib/queues/winners" "github.com/fluidity-money/fluidity-app/lib/types/network" "github.com/fluidity-money/fluidity-app/lib/types/token-details" "github.com/fluidity-money/fluidity-app/lib/util" + + "github.com/fluidity-money/fluidity-app/common/ethereum/fluidity" ) const ( @@ -81,7 +82,6 @@ func main() { } ethereum.Logs(func(log ethereum.Log) { - var ( logTopics = log.Topics transactionHash = log.TxHash diff --git a/cmd/microservice-ethereum-track-winners/processing.go b/cmd/microservice-ethereum-track-winners/processing.go index 4d2a80158..6e6bd45ea 100644 --- a/cmd/microservice-ethereum-track-winners/processing.go +++ b/cmd/microservice-ethereum-track-winners/processing.go @@ -1,9 +1,11 @@ package main import ( + "math" + "math/big" "time" - "github.com/fluidity-money/fluidity-app/common/ethereum/fluidity" + "github.com/fluidity-money/fluidity-app/lib/databases/timescale/lootboxes" winnersDb "github.com/fluidity-money/fluidity-app/lib/databases/timescale/winners" "github.com/fluidity-money/fluidity-app/lib/log" "github.com/fluidity-money/fluidity-app/lib/queue" @@ -12,17 +14,57 @@ import ( "github.com/fluidity-money/fluidity-app/lib/types/network" token_details "github.com/fluidity-money/fluidity-app/lib/types/token-details" "github.com/fluidity-money/fluidity-app/lib/types/winners" + + "github.com/fluidity-money/fluidity-app/common/ethereum/fluidity" ) +func lootboxUpdateTrackedRewardAmounts(lootboxCurrentEpoch string, network_ network.BlockchainNetwork, tokenDetails token_details.TokenDetails, winner winnersDb.Winner) { + var ( + tokenShortName = tokenDetails.TokenShortName + tokenDecimals = tokenDetails.TokenDecimals + + application = winner.Application + amountWon = &winner.WinningAmount.Int + ) + + winnerAddress := "" + + // need to set it to the owner of the ATA if we're on solana! + + switch network_ { + case network.NetworkSolana: + winnerAddress = winner.SolanaWinnerOwnerAddress + + default: + winnerAddress = winner.WinnerAddress + } + + decimals := math.Pow10(tokenDecimals) + + amountNormal := new(big.Rat).SetInt(amountWon) + amountNormal.Quo(amountNormal, new(big.Rat).SetInt64(int64(decimals))) + + amountNormalFloat, _ := amountNormal.Float64() + + lootboxes.UpdateOrInsertAmountsRewarded( + network_, + lootboxCurrentEpoch, + tokenShortName, + amountNormalFloat, // amount normal lossy + winnerAddress, + application, + ) +} + func processReward(contractAddress ethereum.Address, transactionHash ethereum.Hash, data fluidity.RewardData, tokenDetails token_details.TokenDetails, network network.BlockchainNetwork) { var ( - winnerString = data.Winner.String() - winnerAddress = ethereum.AddressFromString(winnerString) - startBlock = *data.StartBlock - endBlock = *data.EndBlock + winnerString = data.Winner.String() + startBlock = *data.StartBlock + endBlock = *data.EndBlock + blocked = data.Blocked ) - blocked := data.Blocked + winnerAddress := ethereum.AddressFromString(winnerString) if blocked { blockedWinner := convertBlockedWinner( @@ -39,6 +81,8 @@ func processReward(contractAddress ethereum.Address, transactionHash ethereum.Ha return } + _, lootboxHasBegun, lootboxCurrentEpoch, _ := lootboxes.GetLootboxConfig() + winners := winnersDb.GetAndRemovePendingRewardData( network, tokenDetails, @@ -57,12 +101,24 @@ func processReward(contractAddress ethereum.Address, transactionHash ethereum.Ha time.Now(), ) + if lootboxHasBegun { + for _, winner := range convertedWinners { + lootboxUpdateTrackedRewardAmounts( + lootboxCurrentEpoch, + network, + tokenDetails, + winner, + ) + } + } + sendRewards(winnersQueue.TopicWinnersEthereum, convertedWinners) } func processUnblockedReward(transactionHash ethereum.Hash, data fluidity.UnblockedRewardData, tokenDetails token_details.TokenDetails, network network.BlockchainNetwork) { + rewardData := data.RewardData + var ( - rewardData = data.RewardData winnerString = rewardData.Winner.String() startBlock = *rewardData.StartBlock endBlock = *rewardData.EndBlock @@ -78,6 +134,8 @@ func processUnblockedReward(transactionHash ethereum.Hash, data fluidity.Unblock winnerAddress, ) + _, lootboxHasBegun, lootboxCurrentEpoch, _ := lootboxes.GetLootboxConfig() + convertedWinners := convertWinners( rewards, transactionHash, @@ -88,6 +146,17 @@ func processUnblockedReward(transactionHash ethereum.Hash, data fluidity.Unblock time.Now(), ) + if lootboxHasBegun { + for _, winner := range convertedWinners { + lootboxUpdateTrackedRewardAmounts( + lootboxCurrentEpoch, + network, + tokenDetails, + winner, + ) + } + } + sendRewards(winnersQueue.TopicWinnersEthereum, convertedWinners) } diff --git a/common/ethereum/applications/jumper/init.go b/common/ethereum/applications/jumper/init.go new file mode 100644 index 000000000..7f0fefc46 --- /dev/null +++ b/common/ethereum/applications/jumper/init.go @@ -0,0 +1,27 @@ +// Copyright 2022 Fluidity Money. All rights reserved. Use of this +// source code is governed by a GPL-style license that can be found in the +// LICENSE.md file. + +package jumper + +import ( + "strings" + + ethAbi "github.com/ethereum/go-ethereum/accounts/abi" +) + +func init() { + reader := strings.NewReader(jumperSwapAbiAbiStr) + + var err error + + if jumperSwapAbi, err = ethAbi.JSON(reader); err != nil { + panic(err) + } + + reader = strings.NewReader(jumperSwapAbiStr) + + if jumperSwapAbiStr, err = ethAbi.JSON(reader); err != nil { + panic(err) + } +} diff --git a/common/ethereum/applications/jumper/jumper.go b/common/ethereum/applications/jumper/jumper.go new file mode 100644 index 000000000..0147a6c55 --- /dev/null +++ b/common/ethereum/applications/jumper/jumper.go @@ -0,0 +1,15 @@ +// Copyright 2022 Fluidity Money. All rights reserved. Use of this +// source code is governed by a GPL-style license that can be found in the +// LICENSE.md file. + +package jumper + +import ( + "fmt" + + ethAbi "github.com/ethereum/go-ethereum/accounts/abi" + ethCommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" +) + +const jumperSwapTopic = "" diff --git a/database/102-up-timescale/20230323164105-airdrop_leaderboard.sql b/database/102-up-timescale/20230323164105-airdrop_leaderboard.sql index fcf1e86ce..750fa4f29 100644 --- a/database/102-up-timescale/20230323164105-airdrop_leaderboard.sql +++ b/database/102-up-timescale/20230323164105-airdrop_leaderboard.sql @@ -14,18 +14,18 @@ LANGUAGE SQL STABLE AS $$ -SELECT +SELECT address, -- placeholder ROW_NUMBER() OVER () AS rank, - COUNT(DISTINCT referee) AS referral_count, - SUM(lootbox_count) AS total_lootboxes, - MAX(reward_tier) AS highest_reward_tier, - COALESCE(liquidity.result, 1) AS liquidity_multiplier -FROM lootbox - LEFT JOIN lootbox_referrals - ON lootbox.address = lootbox_referrals.referrer, - LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity + COUNT(DISTINCT referee) AS referral_count, + SUM(lootbox_count) AS total_lootboxes, + MAX(reward_tier) AS highest_reward_tier, + COALESCE(liquidity.result, 1) AS liquidity_multiplier +FROM lootbox + LEFT JOIN lootbox_referrals + ON lootbox.address = lootbox_referrals.referrer, + LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity GROUP BY address, liquidity_multiplier $$; diff --git a/database/102-up-timescale/20230613063527_airdrop_leaderboard_add_24_hrs_application.sql b/database/102-up-timescale/20230613063527_airdrop_leaderboard_add_24_hrs_application.sql index c9ed1a47a..c1c77eae7 100644 --- a/database/102-up-timescale/20230613063527_airdrop_leaderboard_add_24_hrs_application.sql +++ b/database/102-up-timescale/20230613063527_airdrop_leaderboard_add_24_hrs_application.sql @@ -5,25 +5,25 @@ LANGUAGE SQL STABLE AS $$ -SELECT +SELECT address, -- placeholder ROW_NUMBER() OVER () AS rank, - COUNT(DISTINCT referee) AS referral_count, - lb_24_application.total_box_count, + COUNT(DISTINCT referee) AS referral_count, + lb_24_application.total_box_count, lb_24_application.highest_reward_tier, - COALESCE(liquidity.result, 1) AS liquidity_multiplier + COALESCE(liquidity.result, 1) AS liquidity_multiplier FROM ( -- subquery to avoid re-summing lootbox_count for every referee SELECT address, SUM(lootbox_count) as total_box_count, MAX(reward_tier) as highest_reward_tier - FROM lootbox + FROM lootbox WHERE awarded_time > now() - interval '1 day' - AND application = application_ + AND application = application_ GROUP BY address ) lb_24_application - LEFT JOIN lootbox_referrals - ON lb_24_application.address = lootbox_referrals.referrer, - LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity + LEFT JOIN lootbox_referrals + ON lb_24_application.address = lootbox_referrals.referrer, + LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity GROUP BY address, liquidity_multiplier, total_box_count, highest_reward_tier $$; diff --git a/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql b/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql index 9e7eca0b7..a1587e2de 100644 --- a/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql +++ b/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql @@ -16,15 +16,19 @@ CREATE TABLE lootbox_config ( -- epoch_identifier to use as the identifier for the epoch with -- the enum - epoch_identifier lootbox_epoch NOT NULL, + epoch_identifier lootbox_epoch NOT NULL UNIQUE, -- ethereum_application that should the current focus of the lootbox - -- mini leaderboard competitions + -- mini leaderboard competitions (and should be displayed in the UI + -- with the right query) ethereum_application ethereum_application NOT NULL DEFAULT 'none' ); -INSERT INTO lootbox_config VALUES ( - FALSE, +INSERT INTO lootbox_config ( + program_begin, + program_end, + epoch_identifier +) VALUES ( '2023-05-01 12:00:00+02', '2023-06-28 12:00:00+02', 'epoch_1' diff --git a/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql b/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql new file mode 100644 index 000000000..1edb349bc --- /dev/null +++ b/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql @@ -0,0 +1,31 @@ +-- migrate:up + +-- lootbox_amounts_rewarded is an accumulation table that increases +-- itself over time on a per-epoch basis. it does so so we can track +-- cleanly in the UI the amounts earned for the lootbox presentation + +-- the recipient field is converted from the solana winner owner +-- address implicitly in the go code currently! + +CREATE TABLE lootbox_amounts_rewarded ( + network network_blockchain NOT NULL, + epoch lootbox_epoch NOT NULL, + token_short_name VARCHAR NOT NULL, + + -- the amount earned, normalised according to the underlying + -- decimals. can be lossy + amount_earned DECIMAL NOT NULL, + + -- recipient of the winning amount (the winner) + recipient VARCHAR NOT NULL, + + application VARCHAR NOT NULL, + last_updated TIMESTAMP NOT NULL, + + -- id to prevent duplication during the upsert for updating amounts + CONSTRAINT id PRIMARY KEY(network, epoch, recipient, application) +); + +-- migrate:down + +DROP TABLE lootbox_amounts_rewarded; diff --git a/database/102-up-timescale/20240102213320-airdrop_leaderboard_remove_chronos.sql b/database/102-up-timescale/20240102213320-airdrop_leaderboard_remove_chronos.sql new file mode 100644 index 000000000..c74f30ea6 --- /dev/null +++ b/database/102-up-timescale/20240102213320-airdrop_leaderboard_remove_chronos.sql @@ -0,0 +1,31 @@ +-- migrate:up +DROP FUNCTION airdrop_leaderboard_24_hours_chronos; + +-- migrate:down +CREATE OR REPLACE FUNCTION airdrop_leaderboard_24_hours_chronos() +RETURNS SETOF airdrop_leaderboard_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + address, + -- placeholder + ROW_NUMBER() OVER () AS rank, + COUNT(DISTINCT referee) AS referral_count, + lb_24_chronos.total_box_count, + lb_24_chronos.highest_reward_tier, + COALESCE(liquidity.result, 1) AS liquidity_multiplier +FROM ( + -- subquery to avoid re-summing lootbox_count for every referee + SELECT address, SUM(lootbox_count) as total_box_count, MAX(reward_tier) as highest_reward_tier + FROM lootbox + WHERE awarded_time > now() - interval '1 day' + AND application = 'chronos' + GROUP BY address +) lb_24_chronos + LEFT JOIN lootbox_referrals + ON lb_24_chronos.address = lootbox_referrals.referrer, + LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity +GROUP BY address, liquidity_multiplier, total_box_count, highest_reward_tier +$$; \ No newline at end of file diff --git a/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql b/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql new file mode 100644 index 000000000..66eec0f58 --- /dev/null +++ b/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql @@ -0,0 +1,89 @@ +-- migrate:up + +-- doesn't take the underlying network into account! + +DROP FUNCTION airdrop_leaderboard_24_hours; + +ALTER TABLE airdrop_leaderboard_return + ADD COLUMN fusdc_earned DECIMAL NOT NULL, + ADD COLUMN arb_earned DECIMAL NOT NULL; + +CREATE OR REPLACE FUNCTION airdrop_leaderboard_24_hours(epoch_ lootbox_epoch) +RETURNS SETOF airdrop_leaderboard_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + address, + -- placeholder + ROW_NUMBER() OVER () AS rank, + COUNT(DISTINCT referee) AS referral_count, + lb.total_box_count, + lb.highest_reward_tier, + COALESCE(liquidity.result, 1) AS liquidity_multiplier, + lootbox_amounts_rewarded_fusdc.amount_earned, + lootbox_amounts_rewarded_arb.amount_earned +FROM ( + -- subquery to avoid re-summing lootbox_count for every referee + SELECT address, SUM(lootbox_count) as total_box_count, MAX(reward_tier) as highest_reward_tier + FROM lootbox + WHERE awarded_time > now() - interval '1 day' AND epoch = epoch_ + GROUP BY address +) lb + LEFT JOIN ( + SELECT amount_earned, recipient + FROM lootbox_amounts_rewarded + WHERE token_short_name = 'USDC' + ) AS lootbox_amounts_rewarded_fusdc ON lb.address = lootbox_amounts_rewarded_fusdc.recipient + LEFT JOIN ( + SELECT amount_earned, recipient + FROM lootbox_amounts_rewarded + WHERE token_short_name = 'ARB' + ) AS lootbox_amounts_rewarded_arb ON lb.address = lootbox_amounts_rewarded_arb.recipient + LEFT JOIN lootbox_referrals + ON lb.address = lootbox_referrals.referrer, + LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity +GROUP BY + address, + liquidity_multiplier, + total_box_count, + highest_reward_tier, + lootbox_amounts_rewarded_fusdc.amount_earned, + lootbox_amounts_rewarded_arb.amount_earned +$$; + +-- migrate:down + +DROP FUNCTION airdrop_leaderboard_24_hours; + +ALTER TABLE airdrop_leaderboard_return + DROP COLUMN fusdc_earned, + DROP COLUMN arb_earned; + +CREATE OR REPLACE FUNCTION airdrop_leaderboard_24_hours() +RETURNS SETOF airdrop_leaderboard_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + address, + -- placeholder + ROW_NUMBER() OVER () AS rank, + COUNT(DISTINCT referee) AS referral_count, + lb.total_box_count, + lb.highest_reward_tier, + COALESCE(liquidity.result, 1) AS liquidity_multiplier +FROM ( + -- subquery to avoid re-summing lootbox_count for every referee + SELECT address, SUM(lootbox_count) as total_box_count, MAX(reward_tier) as highest_reward_tier + FROM lootbox + WHERE awarded_time > now() - interval '1 day' + GROUP BY address +) lb + LEFT JOIN lootbox_referrals + ON lb.address = lootbox_referrals.referrer, + LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity +GROUP BY address, liquidity_multiplier, total_box_count, highest_reward_tier +$$; diff --git a/database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_to_24_hours_query.sql b/database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_to_24_hours_query.sql new file mode 100644 index 000000000..94989871f --- /dev/null +++ b/database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_to_24_hours_query.sql @@ -0,0 +1,79 @@ +-- migrate:up + +DROP FUNCTION airdrop_leaderboard_24_hours_by_application; + +CREATE OR REPLACE FUNCTION airdrop_leaderboard_24_hours_by_application(epoch_ lootbox_epoch, application_ ethereum_application) +RETURNS SETOF airdrop_leaderboard_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + address, + -- placeholder + ROW_NUMBER() OVER () AS rank, + COUNT(DISTINCT referee) AS referral_count, + lb_24_application.total_box_count, + lb_24_application.highest_reward_tier, + COALESCE(liquidity.result, 1) AS liquidity_multiplier, + lootbox_amounts_rewarded_fusdc.amount_earned, + lootbox_amounts_rewarded_arb.amount_earned +FROM ( + -- subquery to avoid re-summing lootbox_count for every referee + SELECT address, SUM(lootbox_count) as total_box_count, MAX(reward_tier) as highest_reward_tier + FROM lootbox + WHERE awarded_time > now() - interval '1 day' AND epoch = epoch_ + AND application = application_ + GROUP BY address +) lb_24_application + LEFT JOIN ( + SELECT amount_earned, recipient + FROM lootbox_amounts_rewarded + WHERE token_short_name = 'USDC' + ) AS lootbox_amounts_rewarded_fusdc ON lb_24_application.address = lootbox_amounts_rewarded_fusdc.recipient + LEFT JOIN ( + SELECT amount_earned, recipient + FROM lootbox_amounts_rewarded + WHERE token_short_name = 'ARB' + ) AS lootbox_amounts_rewarded_arb ON lb_24_application.address = lootbox_amounts_rewarded_arb.recipient + LEFT JOIN lootbox_referrals + ON lb_24_application.address = lootbox_referrals.referrer, + LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity +GROUP BY + address, + liquidity_multiplier, + total_box_count, + highest_reward_tier, + lootbox_amounts_rewarded_fusdc.amount_earned, + lootbox_amounts_rewarded_arb.amount_earned +$$; + +-- migrate:down + +CREATE OR REPLACE FUNCTION airdrop_leaderboard_24_hours_by_application(application_ ethereum_application) +RETURNS SETOF airdrop_leaderboard_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + address, + -- placeholder + ROW_NUMBER() OVER () AS rank, + COUNT(DISTINCT referee) AS referral_count, + lb_24_application.total_box_count, + lb_24_application.highest_reward_tier, + COALESCE(liquidity.result, 1) AS liquidity_multiplier +FROM ( + -- subquery to avoid re-summing lootbox_count for every referee + SELECT address, SUM(lootbox_count) as total_box_count, MAX(reward_tier) as highest_reward_tier + FROM lootbox + WHERE awarded_time > now() - interval '1 day' + AND application = application_ + GROUP BY address +) lb_24_application + LEFT JOIN lootbox_referrals + ON lb_24_application.address = lootbox_referrals.referrer, + LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity +GROUP BY address, liquidity_multiplier, total_box_count, highest_reward_tier +$$; \ No newline at end of file diff --git a/lib/databases/timescale/lootboxes/lootboxes.go b/lib/databases/timescale/lootboxes/lootboxes.go index 846399f89..031fc07b3 100644 --- a/lib/databases/timescale/lootboxes/lootboxes.go +++ b/lib/databases/timescale/lootboxes/lootboxes.go @@ -25,6 +25,10 @@ const ( // TableLootboxConfig to use for setting configuration // for the currently running epoch TableLootboxConfig = `lootbox_config` + + // TableLootboxAmountsRewarded to use for tracking cumulative + // amounts earned by users during a lootbox campaign + TableLootboxAmountsRewarded = `lootbox_amounts_rewarded` ) type Lootbox = types.Lootbox diff --git a/lib/databases/timescale/lootboxes/rewards.go b/lib/databases/timescale/lootboxes/rewards.go index 00ae8b518..7d9aa1a25 100644 --- a/lib/databases/timescale/lootboxes/rewards.go +++ b/lib/databases/timescale/lootboxes/rewards.go @@ -13,6 +13,7 @@ import ( "github.com/fluidity-money/fluidity-app/lib/log" "github.com/fluidity-money/fluidity-app/lib/timescale" "github.com/fluidity-money/fluidity-app/lib/types/applications" + "github.com/fluidity-money/fluidity-app/lib/types/network" ) const ExpectedTopUsers = 10 @@ -277,3 +278,54 @@ func GetTopApplicationUsersByLootboxCount(currentEpoch string, startTime, endTim return topUsers } + +// UpdateOrInsertAmountsRewarded for the current user in the specific +// epoch that's taking place. +func UpdateOrInsertAmountsRewarded(network_ network.BlockchainNetwork, lootboxCurrentEpoch, tokenShortName string, amountNormalLossy float64, winnerAddress, application string) { + timescaleClient := timescale.Client() + + statementText := fmt.Sprintf( + `INSERT INTO %s ( + network, + epoch, + token_short_name, + amount_earned, + recipient, + application, + last_updated + ) + VALUES ( + $1, + $2, + $3, + $4, + $5, + $6, + $7 + ) + ON CONFLICT (id) + DO UPDATE SET + amount_earned = amount_earned + $4, + last_updated = CURRENT_TIMESTAMP`, + + TableLootboxAmountsRewarded, + ) + + _, err := timescaleClient.Exec( + statementText, + network_, + lootboxCurrentEpoch, + tokenShortName, + amountNormalLossy, + application, + winnerAddress, + ) + + if err != nil { + log.Fatal(func(k *log.Log) { + k.Context = Context + k.Message = "Failed to upsert a lootbox amount rewarded!" + k.Payload = err + }) + } +} diff --git a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css index 1cf9eb4dd..2e0b9a8ec 100644 --- a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css +++ b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css @@ -1,10 +1,15 @@ .joe_farmlands_or_camelot_div { + display: grid; padding-top: 20px; } +.joe_farmlands_or_camelot_div a { + grid-area: 1/1; + --_p: calc(-1*var(--g)); +} + .joe_farmlands_or_camelot_div img { - position: absolute; width: 100%; border-radius: 10px; } diff --git a/web/app.fluidity.money/app/queries/index.ts b/web/app.fluidity.money/app/queries/index.ts index f71e1a3ea..a959ac1e8 100644 --- a/web/app.fluidity.money/app/queries/index.ts +++ b/web/app.fluidity.money/app/queries/index.ts @@ -9,3 +9,4 @@ export * from "./useReferralCount"; export * from "./addReferral"; export * from "./useReferralCode"; export * from "./addReferralCode"; +export * from "./useLootboxConfig"; diff --git a/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts b/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts index a5326094b..ef21db8b1 100644 --- a/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts +++ b/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts @@ -1,7 +1,10 @@ import { jsonPost, gql, fetchInternalEndpoint } from "~/util"; const queryByUserAllTime = gql` - query AirdropLeaderboard($address: String!) { + query AirdropLeaderboard( + $epoch: String! + $address: String! + ) { airdrop_leaderboard(where: { address: { _eq: $address } }, limit: 1) { user: address rank @@ -14,8 +17,13 @@ const queryByUserAllTime = gql` `; const queryAllTime = gql` - query AirdropLeaderboard { - airdrop_leaderboard(limit: 16, order_by: { total_lootboxes: desc }) { + query AirdropLeaderboard( + $epoch: String! + ) { + airdrop_leaderboard( + args: { epoch_: $epoch } + limit: 16, order_by: { total_lootboxes: desc } + ) { user: address rank referralCount: referral_count @@ -27,8 +35,12 @@ const queryAllTime = gql` `; const queryByUser24Hours = gql` - query AirdropLeaderboard($address: String!) { + query AirdropLeaderboard( + $epoch: String! + $address: String! + ) { airdrop_leaderboard: airdrop_leaderboard_24_hours( + args: { epoch_: $epoch, application_: $application } where: { address: { _eq: $address } } limit: 1 ) { @@ -45,6 +57,7 @@ const queryByUser24Hours = gql` const query24Hours = gql` query AirdropLeaderboard { airdrop_leaderboard: airdrop_leaderboard_24_hours( + args: { epoch_: $epoch } limit: 16 order_by: { total_lootboxes: desc } ) { @@ -60,11 +73,12 @@ const query24Hours = gql` const query24HoursByUserByApplication = gql` query AirdropLeaderboardApplication( + $epoch: String! $application: ethereum_application! $address: String! ) { airdrop_leaderboard: airdrop_leaderboard_24_hours_by_application( - args: { application_: $application } + args: { epoch_: $epoch, application_: $application } where: { address: { _eq: $address } } limit: 1 ) { @@ -79,9 +93,12 @@ const query24HoursByUserByApplication = gql` `; const query24HoursByApplication = gql` - query AirdropLeaderboardByApplication($application: ethereum_application!) { + query AirdropLeaderboardByApplication( + $epoch: String! + $application: ethereum_application! + ) { airdrop_leaderboard: airdrop_leaderboard_24_hours_by_application( - args: { application_: $application } + args: { epoch_: $epoch, application_: $application } limit: 16 order_by: { total_lootboxes: desc } ) { diff --git a/web/app.fluidity.money/app/queries/useLootboxConfig.ts b/web/app.fluidity.money/app/queries/useLootboxConfig.ts new file mode 100644 index 000000000..44b547056 --- /dev/null +++ b/web/app.fluidity.money/app/queries/useLootboxConfig.ts @@ -0,0 +1,41 @@ +import { BottleTiers } from "~/routes/$network/query/dashboard/airdrop"; +import { jsonPost, gql, fetchInternalEndpoint } from "~/util"; + +const queryGetConfig = gql` + query getLootboxConfig() { + lootboxConfig: lootbox_config(where: { is_current_program: true }) { + program_begin, + program_end, + epoch_identifier, + ethereum_application + } + } +`; + +type LootboxConfigBody = { + query: string; +}; + +type LootboxConfigResponse = { + data?: { + programBegin: Date; + programEnd: Date; + epochIdentifier: string; + ethereumApplication: string; + }; + errors?: unknown; +}; + +export const useLootboxConfig = () => { + const { url, headers } = fetchInternalEndpoint(); + + const body = { + query: queryGetConfig, + }; + + return jsonPost( + url, + body, + headers + ); +}; diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/common.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/common.tsx index 4220628c1..e08f617db 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/common.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/common.tsx @@ -1451,7 +1451,7 @@ const tutorialContent: { } = { "0": { title: "WHAT ARE LOOT BOTTLES?", - desc: "Welcome to the Fluidity Airdrop! Use Fluid Assets and earn Loot Bottles. Loot Bottles contain $FLUID tokens. They have different rarities, from common to legendary. The higher the rarity, the more $FLUID tokens it contains. ", + desc: "Welcome to the Fluidity Airdrop V2! Use Fluid Assets and earn Loot Bottles and $ARB rewards. Loot Bottles contain $FLUID tokens. They have different rarities, from common to legendary. The higher the rarity, the more $FLUID tokens it contains. ", image: "WHAT_ARE_LOOT_BOTTLES", }, "1": { diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx index 33b8e3c5c..89f7d7455 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx @@ -49,6 +49,7 @@ import airdropStyle from "~/styles/dashboard/airdrop.css"; import { AirdropLoaderData, BottleTiers } from "../../query/dashboard/airdrop"; import { AirdropLeaderboardLoaderData } from "../../query/dashboard/airdropLeaderboard"; import { ReferralCountLoaderData } from "../../query/referrals"; +import { LootboxConfig } from "../../query/lootboxConfig"; import { AirdropLeaderboardEntry } from "~/queries/useAirdropLeaderboard"; import config from "~/webapp.config.server"; import AugmentedToken from "~/types/AugmentedToken"; @@ -163,6 +164,16 @@ const GLOBAL_AIRDROP_BOTTLE_TIERS = { [Rarity.Legendary]: 5, }; +// defaults lifted from database/20231219094456-lootbox_config_add_prev_epoch.sql +const LOOTBOX_CONFIG_DEFAULT: LootboxConfig = { + found: false, + programBegin: new Date("2023-05-01T12:00:00+02:00"), + programEnd: new Date("2023-06-28 T12:00:00+02:00"), + epochIdentifier: "epoch_1", + ethereumApplication: "none", + loaded: false +}; + const Airdrop = () => { const { epochDaysTotal, @@ -216,6 +227,10 @@ const Airdrop = () => { redeemTokens, } = useContext(FluidityFacadeContext); + const { data: lootboxConfig } = useCache( + `/${network}/query/lootboxConfig` + ); + const { data: airdropData } = useCache( address ? `/${network}/query/dashboard/airdrop?address=${address}` : "" ); @@ -418,10 +433,11 @@ const Airdrop = () => { const [localShouldShowBottleNumbers, setLocalShouldShowBottleNumbers] = useState(undefined); - // const [localShouldShowTutorial, setLocalShouldShowTutorial] = useState< - // boolean | undefined - // >(undefined); - const localShouldShowTutorial = false; + + const [localShouldShowTutorial, setLocalShouldShowTutorial] = useState< + boolean | undefined + >(undefined); + const [localShouldShowRecapIntro, setLocalShouldShowRecapIntro] = useState< boolean | undefined >(undefined); @@ -437,9 +453,11 @@ const Airdrop = () => { setLocalCookieConsent(true); } - // const airdropHasVisited = window.localStorage.getItem("airdropHasVisited"); + const airdropHasVisited = window.localStorage.getItem("airdropHasVisited"); + const airdropBottleCount = window.localStorage.getItem("airdropBottleCount"); + const airdropShouldShowBottleNumbers = window.localStorage.getItem( "airdropShouldShowBottleNumbers" ); @@ -462,17 +480,8 @@ const Airdrop = () => { "airdropShouldShowRecapIntro" ); - if (airdropShouldShowRecapIntro) { - setLocalShouldShowRecapIntro(false); - } else { - setLocalShouldShowRecapIntro(true); - } - - // if (airdropHasVisited) { - // setLocalShouldShowTutorial(false); - // } else { - // setLocalShouldShowTutorial(true); - // } + setLocalShouldShowRecapIntro(!airdropShouldShowRecapIntro); + setLocalShouldShowTutorial(!airdropHasVisited); }, []); useEffect(() => { @@ -618,7 +627,6 @@ const Airdrop = () => { {currentModal === null && ( <>
- { ) : ( <>
+
+ +
{ const { address } = useContext(FluidityFacadeContext); - const { user, rank, referralCount, liquidityMultiplier, bottles } = data; + const { user, rank, referralCount, fusdcEarned, arbEarned, bottles } = data; return { className: `airdrop-row ${isMobile ? "airdrop-mobile" : ""} ${ @@ -1432,7 +1453,24 @@ const airdropRankRow = ( ); - case "STAKING MULTIPLIER": + case "FUSDC EARNED": + return ( + + + {toSignificantDecimals(fusdcEarned, 0)}x + + + ); + case "ARB EARNED": return ( - {toSignificantDecimals(liquidityMultiplier, 1)}x + {toSignificantDecimals(arbEarned, 0)}x ); @@ -1565,7 +1603,8 @@ const Leaderboard = ({ { name: "RANK" }, { name: "USER" }, { name: "BOTTLES" }, - { name: "STAKING MULTIPLIER" }, + { name: "$fUSDC EARNED" }, + { name: "$ARB EARNED" }, { name: "REFERRALS" }, ]} pagination={{ diff --git a/web/app.fluidity.money/app/routes/$network/query/lootboxConfig.tsx b/web/app.fluidity.money/app/routes/$network/query/lootboxConfig.tsx new file mode 100644 index 000000000..092bffa9b --- /dev/null +++ b/web/app.fluidity.money/app/routes/$network/query/lootboxConfig.tsx @@ -0,0 +1,51 @@ +import { LoaderFunction, json } from "@remix-run/node"; +import { captureException } from "@sentry/react"; +import config from "~/webapp.config.server"; +import { useLootboxConfig } from "~/queries"; + +export type LootboxConfig = { + found: boolean; + programBegin: Date; + programEnd: Date; + epochIdentifier: string; + ethereumApplication: string; + loaded: boolean; +}; + +export const loader: LoaderFunction = async ({ params, request }) => { + const { network } = params; + + const url = new URL(request.url); + + try { + const { data, errors } = await useLootboxConfig(); + + if (errors || !data) { + captureException(errors, { + tags: { + section: "airdrop", + }, + }); + + return new Error("Server could not fulfill request"); + } + + const { programBegin, programEnd, epochIdentifier, ethereumApplication } = data; + + return json({ + found: true, + programBegin, + programEnd, + epochIdentifier, + ethereumApplication, + loaded: true, + } satisfies LootboxConfig); + } catch (err) { + captureException(new Error(`Could not fetch lootbox config: ${err}`), { + tags: { + section: "network/index", + }, + }); + return new Error("Server could not fulfill request"); + } +}; diff --git a/web/app.fluidity.money/contexts/LootboxProvider.tsx b/web/app.fluidity.money/contexts/LootboxProvider.tsx new file mode 100644 index 000000000..e0256773b --- /dev/null +++ b/web/app.fluidity.money/contexts/LootboxProvider.tsx @@ -0,0 +1,22 @@ + +import { createContext } from "react"; + +type LootboxType = { + epochName: string +}; + +const LootboxContext = createContext({ epochName: "" }); + +interface ILootboxProviderProps { + children: React.ReactNode; +} + +const LootboxProvider = ({ children }: ILootboxProviderProps) => { + return ( + <> + + + ); +}; + +export default LootboxProvider; diff --git a/web/app.fluidity.money/public/images/epoch2AirdropBanner.png b/web/app.fluidity.money/public/images/epoch2AirdropBanner.png index 4e001da53..eb7a4eb31 100644 --- a/web/app.fluidity.money/public/images/epoch2AirdropBanner.png +++ b/web/app.fluidity.money/public/images/epoch2AirdropBanner.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c62d475e73da37820d1653cbca3f8318cfcea7eb2869e639a61c83805727a397 -size 696368 +oid sha256:72209eaa5f613befc0b8fcc53d66b42693d48fa565404b028dcab5034a9fe1fc +size 170872 diff --git a/web/app.fluidity.money/public/images/hero/common.png b/web/app.fluidity.money/public/images/hero/common.png index afb7e2da1..9651b6b77 100644 --- a/web/app.fluidity.money/public/images/hero/common.png +++ b/web/app.fluidity.money/public/images/hero/common.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cf873fc5dbc6f6493a8729e240d33026022a45def8c53c5d847873b1bb01bd5c -size 267816 +oid sha256:fbfdf8c12d6b02bad36eca229eadffb462b819d39b0a8385de3b864a85f83814 +size 167937 diff --git a/web/app.fluidity.money/public/images/hero/legendary.png b/web/app.fluidity.money/public/images/hero/legendary.png index 06fb62a20..a38f1a1f6 100644 --- a/web/app.fluidity.money/public/images/hero/legendary.png +++ b/web/app.fluidity.money/public/images/hero/legendary.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:252ea1e42636e41520a4e003056825f11e77ecf39f0766f93b6d2b6005eedfd3 -size 882592 +oid sha256:cfb9fdce40d47bd56d85f36f53f890113c97d48b52f35cf3a1772077c95132f4 +size 216190 diff --git a/web/app.fluidity.money/public/images/hero/rare.png b/web/app.fluidity.money/public/images/hero/rare.png index 282a12a3c..8b80c9ea0 100644 --- a/web/app.fluidity.money/public/images/hero/rare.png +++ b/web/app.fluidity.money/public/images/hero/rare.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:246725e96442ac0ac7e5aeafd33415937c1984eed2b83a6cb839dcf8e0dce6d6 -size 209084 +oid sha256:60677247e65f4ce979c7b4a709e51d310285f5bc6a971f753710e7cddc301439 +size 157634 diff --git a/web/app.fluidity.money/public/images/hero/ultra_rare.png b/web/app.fluidity.money/public/images/hero/ultra_rare.png index c90a7c963..96c422d32 100644 --- a/web/app.fluidity.money/public/images/hero/ultra_rare.png +++ b/web/app.fluidity.money/public/images/hero/ultra_rare.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:872c19d8fa54a4f59c7d11ba9dd3f84870f6955e817b8c8c91d1d866dbd49265 -size 241863 +oid sha256:576235a66a879f45a55773b95591a0a78c022b15aa82a41c7674471e6284bd76 +size 169854 diff --git a/web/app.fluidity.money/public/images/hero/uncommon.png b/web/app.fluidity.money/public/images/hero/uncommon.png index ad5d7c2fa..0010e8234 100644 --- a/web/app.fluidity.money/public/images/hero/uncommon.png +++ b/web/app.fluidity.money/public/images/hero/uncommon.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:238e51be54c715fbb00d8233d809cd6d4ff6e6a05fdd581d95c28a5c6344dabe -size 259633 +oid sha256:c2e149ca67b2f012270d78c53bbf2f052de5cc41c799c73a5698cebd16bb8649 +size 177534 diff --git a/web/surfing/src/util/liquidityProviders/providers.ts b/web/surfing/src/util/liquidityProviders/providers.ts index cfc62858e..1efa6c316 100644 --- a/web/surfing/src/util/liquidityProviders/providers.ts +++ b/web/surfing/src/util/liquidityProviders/providers.ts @@ -17,6 +17,7 @@ const providerImgNames: { [K in Provider]: string } = { Curve: "curve.png", Dodo: "DODO.png", Fluidity: "logoMetallic.png", + Jumper: "Jumper.svg", Jupiter: "Jupiter.svg", Kyber: "Kyber.svg", Lemniscap: "Lemniscap.png", @@ -29,6 +30,7 @@ const providerImgNames: { [K in Provider]: string } = { Oneinch: "1inch.svg", Orca: "Orca.svg", Polygon: "Polygon.svg", + Ramses: "Ramses.svg", Raydium: "raydium.png", Saber: "Saber.svg", Saddle: "Saddle.svg", From 98049519bd9dfd7ac241376c103f3464b60566d3 Mon Sep 17 00:00:00 2001 From: user Date: Wed, 3 Jan 2024 16:38:02 +1030 Subject: [PATCH 05/18] Fix a few mistakes --- .../20231228172908-lootbox_amounts_earned_create.sql | 4 ++-- .../app/queries/useAirdropLeaderboard.ts | 12 ++++++++++++ .../app/queries/useLootboxConfig.ts | 4 ++-- .../app/routes/$network/dashboard/airdrop/index.tsx | 4 +++- .../$network/query/dashboard/airdropLeaderboard.tsx | 2 ++ 5 files changed, 21 insertions(+), 5 deletions(-) diff --git a/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql b/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql index 1edb349bc..adf2375fa 100644 --- a/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql +++ b/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql @@ -20,10 +20,10 @@ CREATE TABLE lootbox_amounts_rewarded ( recipient VARCHAR NOT NULL, application VARCHAR NOT NULL, - last_updated TIMESTAMP NOT NULL, + last_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- id to prevent duplication during the upsert for updating amounts - CONSTRAINT id PRIMARY KEY(network, epoch, recipient, application) + CONSTRAINT id PRIMARY KEY(network, epoch, token_short_name, recipient, application) ); -- migrate:down diff --git a/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts b/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts index ef21db8b1..7435e468c 100644 --- a/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts +++ b/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts @@ -30,6 +30,8 @@ const queryAllTime = gql` bottles: total_lootboxes highestRewardTier: highest_reward_tier liquidityMultiplier: liquidity_multiplier + fusdcEarned: fusdc_earned + arbEarned: arb_earned } } `; @@ -50,6 +52,8 @@ const queryByUser24Hours = gql` bottles: total_lootboxes highestRewardTier: highest_reward_tier liquidityMultiplier: liquidity_multiplier + fusdcEarned: fusdc_earned + arbEarned: arb_earned } } `; @@ -67,6 +71,8 @@ const query24Hours = gql` bottles: total_lootboxes highestRewardTier: highest_reward_tier liquidityMultiplier: liquidity_multiplier + fusdcEarned: fusdc_earned + arbEarned: arb_earned } } `; @@ -88,6 +94,8 @@ const query24HoursByUserByApplication = gql` bottles: total_lootboxes highestRewardTier: highest_reward_tier liquidityMultiplier: liquidity_multiplier + fusdcEarned: fusdc_earned + arbEarned: arb_earned } } `; @@ -108,6 +116,8 @@ const query24HoursByApplication = gql` bottles: total_lootboxes highestRewardTier: highest_reward_tier liquidityMultiplier: liquidity_multiplier + fusdcEarned: fusdc_earned + arbEarned: arb_earned } } `; @@ -142,6 +152,8 @@ export type AirdropLeaderboardEntry = { bottles: number; highestRewardTier: number; liquidityMultiplier: number; + fusdcEarned: number; + arbEarned: number; }; type AirdropLeaderboardResponse = { diff --git a/web/app.fluidity.money/app/queries/useLootboxConfig.ts b/web/app.fluidity.money/app/queries/useLootboxConfig.ts index 44b547056..68a18f0e6 100644 --- a/web/app.fluidity.money/app/queries/useLootboxConfig.ts +++ b/web/app.fluidity.money/app/queries/useLootboxConfig.ts @@ -2,8 +2,8 @@ import { BottleTiers } from "~/routes/$network/query/dashboard/airdrop"; import { jsonPost, gql, fetchInternalEndpoint } from "~/util"; const queryGetConfig = gql` - query getLootboxConfig() { - lootboxConfig: lootbox_config(where: { is_current_program: true }) { + query getLootboxConfig { + lootboxConfig: lootbox_config(where: { is_current_program: { _eq: true }}) { program_begin, program_end, epoch_identifier, diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx index 89f7d7455..0de30267c 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx @@ -227,7 +227,7 @@ const Airdrop = () => { redeemTokens, } = useContext(FluidityFacadeContext); - const { data: lootboxConfig } = useCache( + const { data: lootboxConfig } = useCache( `/${network}/query/lootboxConfig` ); @@ -1541,6 +1541,8 @@ const Leaderboard = ({ liquidityMultiplier: 0, bottles: 0, highestRewardTier: 0, + fusdcEarned: 0, + arbEarned: 0 }; data.push(userEntry); diff --git a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx index f7836405e..293c8f1a7 100644 --- a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx @@ -105,6 +105,8 @@ export const loader: LoaderFunction = async ({ params, request }) => { referralCount: 0, bottles: 0, highestRewardTier: 0, + fusdcEarned: 0, + arbEarned: 0 } satisfies AirdropLeaderboardEntry, ] ).concat(leaderboard); From 15428c4dd288e242ebeb9e509c4ecb8510b52465 Mon Sep 17 00:00:00 2001 From: user Date: Fri, 5 Jan 2024 19:19:33 +1030 Subject: [PATCH 06/18] Rotate around the location of the epochs and add more to frontend --- .../README.md | 2 +- .../main.go | 64 ++++++++++++- .../+Errors | 4 + .../main.go | 16 +++- .../README.md | 3 - .../processing.go | 67 ------------- .../main.go | 9 +- .../main.go | 13 ++- .../20231219091930-lootbox_add_epoch.sql | 89 +++++++++--------- ...28172908-lootbox_amounts_earned_create.sql | 3 + ...board_24_hours_add_epoch_and_arb_fusdc.sql | 6 +- ...p_leaderboard_add_epoch_and_arb_fusdc.sql} | 6 +- ...0240104203505-lootbox_counts_add_epoch.sql | 81 ++++++++++++++++ ...05003308-airdrop_leaderboard_add_epoch.sql | 72 ++++++++++++++ .../app/queries/addReferral.ts | 2 +- .../app/queries/addReferralCode.ts | 2 +- .../app/queries/useAirdropLeaderboard.ts | 28 ++++-- .../app/queries/useAirdropStats.ts | 12 ++- .../queries/useApplicationRewardStatistics.ts | 2 +- .../app/queries/useAssetStatistics.ts | 2 +- .../app/queries/useGlobalRewardStatistics.ts | 2 +- .../app/queries/useHighestRewardStatistics.ts | 4 +- .../app/queries/useLootBottles.ts | 2 +- .../app/queries/useLootBottlesCount.ts | 11 ++- .../app/queries/useLootboxConfig.ts | 60 +++++++++--- .../app/queries/useReferralCode.ts | 4 +- .../app/queries/useReferralCount.ts | 6 +- .../app/queries/useReferrals.ts | 4 +- .../app/queries/useStakingData.ts | 2 +- .../app/queries/useTokenRewardStatistics.ts | 2 +- .../app/queries/useTokens.ts | 2 +- .../app/queries/useUserRewards.ts | 8 +- .../app/queries/useUserUnclaimedRewards.ts | 2 +- .../app/queries/useUserYield.ts | 4 +- .../app/queries/useVolumeStats.ts | 4 +- .../app/routes/$network/dashboard.tsx | 76 +++++++-------- .../$network/dashboard/airdrop/index.tsx | 94 +++++++------------ .../app/routes/$network/dashboard/home.tsx | 18 ++++ .../$network/query/dashboard/airdrop.tsx | 87 ++++++++++++----- .../query/dashboard/airdropLeaderboard.tsx | 19 ++-- .../routes/$network/query/lootboxConfig.tsx | 51 ---------- .../routes/$network/query/referralBottles.tsx | 8 +- .../app/styles/dashboard.css | 5 + .../app/styles/dashboard.scss | 5 + .../app/util/api/graphql.ts | 6 +- .../util/chainUtils/ethereum/transaction.ts | 8 +- .../contexts/LootboxProvider.tsx | 22 ----- 47 files changed, 597 insertions(+), 402 deletions(-) create mode 100644 cmd/microservice-ethereum-create-transaction-lootboxes/+Errors rename database/102-up-timescale/{20240103103945-airdrop_leaderboard_add_epoch_to_24_hours_query.sql => 20240103103945-airdrop_leaderboard_add_epoch_and_arb_fusdc.sql} (91%) create mode 100644 database/102-up-timescale/20240104203505-lootbox_counts_add_epoch.sql create mode 100644 database/102-up-timescale/20240105003308-airdrop_leaderboard_add_epoch.sql delete mode 100644 web/app.fluidity.money/app/routes/$network/query/lootboxConfig.tsx delete mode 100644 web/app.fluidity.money/contexts/LootboxProvider.tsx diff --git a/cmd/connector-common-winners-timescale/README.md b/cmd/connector-common-winners-timescale/README.md index 455a15be3..58683806b 100644 --- a/cmd/connector-common-winners-timescale/README.md +++ b/cmd/connector-common-winners-timescale/README.md @@ -1,7 +1,7 @@ # Winners to Timescale connector -Write winners received via AMQP to Timescale. +Write winners received via AMQP to Timescale. Also tracks epochs. ## Environment variables diff --git a/cmd/connector-common-winners-timescale/main.go b/cmd/connector-common-winners-timescale/main.go index 0e389ab18..5f35ef4b3 100644 --- a/cmd/connector-common-winners-timescale/main.go +++ b/cmd/connector-common-winners-timescale/main.go @@ -5,17 +5,79 @@ package main import ( + "math" + "math/big" + + "github.com/fluidity-money/fluidity-app/lib/log" "github.com/fluidity-money/fluidity-app/lib/databases/postgres/solana" + "github.com/fluidity-money/fluidity-app/lib/databases/timescale/lootboxes" database "github.com/fluidity-money/fluidity-app/lib/databases/timescale/winners" queue "github.com/fluidity-money/fluidity-app/lib/queues/winners" + "github.com/fluidity-money/fluidity-app/lib/types/network" ) +func lootboxUpdateTrackedRewardAmounts(winner queue.Winner) { + var ( + network_ = winner.Network + tokenDetails = winner.TokenDetails + application = winner.Application + amountWon = &winner.WinningAmount.Int + ) + + _, lootboxHasBegun, lootboxCurrentEpoch, _ := lootboxes.GetLootboxConfig() + + if !lootboxHasBegun { + log.Debug(func(k *log.Log) { + k.Message = "Lootbox not running! Ignoring a winner to be inserted in the lootbox tracked rewards!" + }) + + return + } + + var ( + tokenShortName = tokenDetails.TokenShortName + tokenDecimals = tokenDetails.TokenDecimals + ) + + winnerAddress := "" + + // need to set it to the owner of the ATA if we're on solana! + + switch network_ { + case network.NetworkSolana: + winnerAddress = winner.SolanaWinnerOwnerAddress + + default: + winnerAddress = winner.WinnerAddress + } + + decimals := math.Pow10(tokenDecimals) + + amountNormal := new(big.Rat).SetInt(amountWon) + amountNormal.Quo(amountNormal, new(big.Rat).SetInt64(int64(decimals))) + + amountNormalFloat, _ := amountNormal.Float64() + + lootboxes.UpdateOrInsertAmountsRewarded( + network_, + lootboxCurrentEpoch, + tokenShortName, + amountNormalFloat, // amount normal lossy + winnerAddress, + application, + ) +} + func main() { - go queue.WinnersEthereum(database.InsertWinner) + go queue.WinnersEthereum(func(winner queue.Winner) { + lootboxUpdateTrackedRewardAmounts(winner) + database.InsertWinner(winner) + }) queue.WinnersSolana(func(winner queue.Winner) { winningSignature := solana.GetIntermediateWinner(winner.TransactionHash) winner.SendTransactionHash = winningSignature + lootboxUpdateTrackedRewardAmounts(winner) database.InsertWinner(winner) }) } diff --git a/cmd/microservice-ethereum-create-transaction-lootboxes/+Errors b/cmd/microservice-ethereum-create-transaction-lootboxes/+Errors new file mode 100644 index 000000000..794938511 --- /dev/null +++ b/cmd/microservice-ethereum-create-transaction-lootboxes/+Errors @@ -0,0 +1,4 @@ +//: Permission denied +: exit 1 +//: Permission denied +//: Permission denied diff --git a/cmd/microservice-ethereum-create-transaction-lootboxes/main.go b/cmd/microservice-ethereum-create-transaction-lootboxes/main.go index b3fb5a3d0..a523578a7 100644 --- a/cmd/microservice-ethereum-create-transaction-lootboxes/main.go +++ b/cmd/microservice-ethereum-create-transaction-lootboxes/main.go @@ -89,17 +89,23 @@ func main() { programFound, hasBegun, currentEpoch, _ := database.GetLootboxConfig() - if !programFound { + // check that the lootbox is enabled, and that it's also + // running. logs separately if either fail. if the + // campaign has begun but isn't in progress, then we + // should die! that means that something was processed + // weirdly. + + switch false { + case programFound: log.App(func(k *log.Log) { - k.Message = "No lootbox epoch found, ignoring a request to track winners!" + k.Message = "No lootbox epoch found, skipping a request to track a winner!" }) return - } - if hasBegun { + case hasBegun: log.Fatal(func(k *log.Log) { - k.Message = "Lootbox epoch that was found is not running! Ignoring a request to track!" + k.Message = "Lootbox epoch that was found is not running! Terminating on request to track a winner!" }) return diff --git a/cmd/microservice-ethereum-track-winners/README.md b/cmd/microservice-ethereum-track-winners/README.md index 3ff8ba720..f39476d27 100644 --- a/cmd/microservice-ethereum-track-winners/README.md +++ b/cmd/microservice-ethereum-track-winners/README.md @@ -4,9 +4,6 @@ Take a list of contracts to watch and report when one of them generates a `Reward` event. -Tracks the amounts earned in the database, after scanning the current -airdrop epoch, if any. - ## Environment variables | Name | Description diff --git a/cmd/microservice-ethereum-track-winners/processing.go b/cmd/microservice-ethereum-track-winners/processing.go index 6e6bd45ea..d976b96af 100644 --- a/cmd/microservice-ethereum-track-winners/processing.go +++ b/cmd/microservice-ethereum-track-winners/processing.go @@ -1,11 +1,8 @@ package main import ( - "math" - "math/big" "time" - "github.com/fluidity-money/fluidity-app/lib/databases/timescale/lootboxes" winnersDb "github.com/fluidity-money/fluidity-app/lib/databases/timescale/winners" "github.com/fluidity-money/fluidity-app/lib/log" "github.com/fluidity-money/fluidity-app/lib/queue" @@ -18,44 +15,6 @@ import ( "github.com/fluidity-money/fluidity-app/common/ethereum/fluidity" ) -func lootboxUpdateTrackedRewardAmounts(lootboxCurrentEpoch string, network_ network.BlockchainNetwork, tokenDetails token_details.TokenDetails, winner winnersDb.Winner) { - var ( - tokenShortName = tokenDetails.TokenShortName - tokenDecimals = tokenDetails.TokenDecimals - - application = winner.Application - amountWon = &winner.WinningAmount.Int - ) - - winnerAddress := "" - - // need to set it to the owner of the ATA if we're on solana! - - switch network_ { - case network.NetworkSolana: - winnerAddress = winner.SolanaWinnerOwnerAddress - - default: - winnerAddress = winner.WinnerAddress - } - - decimals := math.Pow10(tokenDecimals) - - amountNormal := new(big.Rat).SetInt(amountWon) - amountNormal.Quo(amountNormal, new(big.Rat).SetInt64(int64(decimals))) - - amountNormalFloat, _ := amountNormal.Float64() - - lootboxes.UpdateOrInsertAmountsRewarded( - network_, - lootboxCurrentEpoch, - tokenShortName, - amountNormalFloat, // amount normal lossy - winnerAddress, - application, - ) -} - func processReward(contractAddress ethereum.Address, transactionHash ethereum.Hash, data fluidity.RewardData, tokenDetails token_details.TokenDetails, network network.BlockchainNetwork) { var ( winnerString = data.Winner.String() @@ -81,8 +40,6 @@ func processReward(contractAddress ethereum.Address, transactionHash ethereum.Ha return } - _, lootboxHasBegun, lootboxCurrentEpoch, _ := lootboxes.GetLootboxConfig() - winners := winnersDb.GetAndRemovePendingRewardData( network, tokenDetails, @@ -101,17 +58,6 @@ func processReward(contractAddress ethereum.Address, transactionHash ethereum.Ha time.Now(), ) - if lootboxHasBegun { - for _, winner := range convertedWinners { - lootboxUpdateTrackedRewardAmounts( - lootboxCurrentEpoch, - network, - tokenDetails, - winner, - ) - } - } - sendRewards(winnersQueue.TopicWinnersEthereum, convertedWinners) } @@ -134,8 +80,6 @@ func processUnblockedReward(transactionHash ethereum.Hash, data fluidity.Unblock winnerAddress, ) - _, lootboxHasBegun, lootboxCurrentEpoch, _ := lootboxes.GetLootboxConfig() - convertedWinners := convertWinners( rewards, transactionHash, @@ -146,17 +90,6 @@ func processUnblockedReward(transactionHash ethereum.Hash, data fluidity.Unblock time.Now(), ) - if lootboxHasBegun { - for _, winner := range convertedWinners { - lootboxUpdateTrackedRewardAmounts( - lootboxCurrentEpoch, - network, - tokenDetails, - winner, - ) - } - } - sendRewards(winnersQueue.TopicWinnersEthereum, convertedWinners) } diff --git a/cmd/microservice-lootbox-reward-top-winners/main.go b/cmd/microservice-lootbox-reward-top-winners/main.go index 35d831bcc..d5516f77b 100644 --- a/cmd/microservice-lootbox-reward-top-winners/main.go +++ b/cmd/microservice-lootbox-reward-top-winners/main.go @@ -34,15 +34,18 @@ func main() { programFound, hasBegun, currentEpoch, currentApplication := lootboxes.GetLootboxConfig() - if !programFound { + // if the lootbox isn't enabled, or it isn't running, then we skip. we + // treat the cases separately for logging reasons. + + switch false { + case programFound: log.App(func(k *log.Log) { k.Message = "No lootbox epoch found! Skipping running." }) return - } - if !hasBegun { + case hasBegun: log.App(func(k *log.Log) { k.Message = "Current lootbox epoch has not yet started! Skipping running." }) diff --git a/cmd/microservice-redeem-testnet-lootboxes/main.go b/cmd/microservice-redeem-testnet-lootboxes/main.go index 7d5b7e997..0c059b335 100644 --- a/cmd/microservice-redeem-testnet-lootboxes/main.go +++ b/cmd/microservice-redeem-testnet-lootboxes/main.go @@ -34,17 +34,20 @@ func main() { ) logs.Logs(func(l logs.Log) { - // if a user encounters this, how did they get here? - programFound, hasBegun, currentEpoch, _ := lootboxes.GetLootboxConfig() - if !programFound { + // if the lootbox isn't enabled, or it isn't running, then we alarm + // because someone has called the contract to manually reward themselves + // whem presumably the UI isn't enabled. treated separately for logging + // reasons. + + switch false { + case programFound: log.Fatal(func(k *log.Log) { k.Message = "No lootbox program found, but a log was received for a testnet redemption!" }) - } - if hasBegun { + case hasBegun: log.Fatal(func(k *log.Log) { k.Message = "Lootbox program that was found is not running!" }) diff --git a/database/102-up-timescale/20231219091930-lootbox_add_epoch.sql b/database/102-up-timescale/20231219091930-lootbox_add_epoch.sql index df28fe5e4..ba3523d0c 100644 --- a/database/102-up-timescale/20231219091930-lootbox_add_epoch.sql +++ b/database/102-up-timescale/20231219091930-lootbox_add_epoch.sql @@ -25,31 +25,34 @@ STABLE AS $$ SELECT - address, - COALESCE(tier1, 0), - COALESCE(tier2, 0), - COALESCE(tier3, 0), - COALESCE(tier4, 0), - COALESCE(tier5, 0) -FROM crosstab( - 'SELECT address, - reward_tier, - SUM(lootbox_count) - FROM lootbox - WHERE source=''referral'' AND epoch = epoch_ - GROUP BY - address, - reward_tier - ORDER BY 1', - 'VALUES (1),(2),(3),(4),(5)' + COALESCE(tier1, 0), + COALESCE(tier2, 0), + COALESCE(tier3, 0), + COALESCE(tier4, 0), + COALESCE(tier5, 0) +FROM crosstab( + format( + 'SELECT + address, + reward_tier, + SUM(lootbox_count) + FROM lootbox + WHERE source=''referral'' AND epoch = %s + GROUP BY + address, + reward_tier + ORDER BY 1', + quote_literal(epoch_) + ), + 'VALUES (1),(2),(3),(4),(5)' ) AS ct( - address VARCHAR, - tier1 NUMERIC, - tier2 NUMERIC, - tier3 NUMERIC, - tier4 NUMERIC, - tier5 NUMERIC + address VARCHAR, + tier1 NUMERIC, + tier2 NUMERIC, + tier3 NUMERIC, + tier4 NUMERIC, + tier5 NUMERIC ); $$; @@ -70,30 +73,30 @@ STABLE AS $$ SELECT - address, - COALESCE(tier1, 0), - COALESCE(tier2, 0), - COALESCE(tier3, 0), - COALESCE(tier4, 0), - COALESCE(tier5, 0) + address, + COALESCE(tier1, 0), + COALESCE(tier2, 0), + COALESCE(tier3, 0), + COALESCE(tier4, 0), + COALESCE(tier5, 0) FROM crosstab( - 'SELECT + 'SELECT address, reward_tier, SUM(lootbox_count) - FROM lootbox - WHERE source=''referral'' - GROUP BY - address, - reward_tier - ORDER BY 1', - 'VALUES (1),(2),(3),(4),(5)' + FROM lootbox + WHERE source=''referral'' + GROUP BY + address, + reward_tier + ORDER BY 1', + 'VALUES (1),(2),(3),(4),(5)' ) AS ct( - address VARCHAR, - tier1 NUMERIC, - tier2 NUMERIC, - tier3 NUMERIC, - tier4 NUMERIC, - tier5 NUMERIC + address VARCHAR, + tier1 NUMERIC, + tier2 NUMERIC, + tier3 NUMERIC, + tier4 NUMERIC, + tier5 NUMERIC ); $$; diff --git a/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql b/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql index adf2375fa..dec7a2b8b 100644 --- a/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql +++ b/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql @@ -7,6 +7,9 @@ -- the recipient field is converted from the solana winner owner -- address implicitly in the go code currently! +-- we're okay with DECIMAL as we can store the floating amount with a +-- level of loss since this is user-facing. + CREATE TABLE lootbox_amounts_rewarded ( network network_blockchain NOT NULL, epoch lootbox_epoch NOT NULL, diff --git a/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql b/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql index 66eec0f58..77387d0ae 100644 --- a/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql +++ b/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql @@ -8,7 +8,7 @@ ALTER TABLE airdrop_leaderboard_return ADD COLUMN fusdc_earned DECIMAL NOT NULL, ADD COLUMN arb_earned DECIMAL NOT NULL; -CREATE OR REPLACE FUNCTION airdrop_leaderboard_24_hours(epoch_ lootbox_epoch) +CREATE FUNCTION airdrop_leaderboard_24_hours(epoch_ lootbox_epoch) RETURNS SETOF airdrop_leaderboard_return LANGUAGE SQL STABLE @@ -22,8 +22,8 @@ SELECT lb.total_box_count, lb.highest_reward_tier, COALESCE(liquidity.result, 1) AS liquidity_multiplier, - lootbox_amounts_rewarded_fusdc.amount_earned, - lootbox_amounts_rewarded_arb.amount_earned + COALESCE(lootbox_amounts_rewarded_fusdc.amount_earned, 0), + COALESCE(lootbox_amounts_rewarded_arb.amount_earned, 0) FROM ( -- subquery to avoid re-summing lootbox_count for every referee SELECT address, SUM(lootbox_count) as total_box_count, MAX(reward_tier) as highest_reward_tier diff --git a/database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_to_24_hours_query.sql b/database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_and_arb_fusdc.sql similarity index 91% rename from database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_to_24_hours_query.sql rename to database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_and_arb_fusdc.sql index 94989871f..d145a40c3 100644 --- a/database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_to_24_hours_query.sql +++ b/database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_and_arb_fusdc.sql @@ -2,7 +2,7 @@ DROP FUNCTION airdrop_leaderboard_24_hours_by_application; -CREATE OR REPLACE FUNCTION airdrop_leaderboard_24_hours_by_application(epoch_ lootbox_epoch, application_ ethereum_application) +CREATE FUNCTION airdrop_leaderboard_24_hours_by_application(epoch_ lootbox_epoch, application_ ethereum_application) RETURNS SETOF airdrop_leaderboard_return LANGUAGE SQL STABLE @@ -16,8 +16,8 @@ SELECT lb_24_application.total_box_count, lb_24_application.highest_reward_tier, COALESCE(liquidity.result, 1) AS liquidity_multiplier, - lootbox_amounts_rewarded_fusdc.amount_earned, - lootbox_amounts_rewarded_arb.amount_earned + COALESCE(lootbox_amounts_rewarded_fusdc.amount_earned, 0), + COALESCE(lootbox_amounts_rewarded_arb.amount_earned, 0) FROM ( -- subquery to avoid re-summing lootbox_count for every referee SELECT address, SUM(lootbox_count) as total_box_count, MAX(reward_tier) as highest_reward_tier diff --git a/database/102-up-timescale/20240104203505-lootbox_counts_add_epoch.sql b/database/102-up-timescale/20240104203505-lootbox_counts_add_epoch.sql new file mode 100644 index 000000000..2d68b232c --- /dev/null +++ b/database/102-up-timescale/20240104203505-lootbox_counts_add_epoch.sql @@ -0,0 +1,81 @@ +--migrate:up + +DROP FUNCTION lootbox_counts; + +-- epoch should be sanitised as an argument here + +CREATE FUNCTION lootbox_counts(epoch_ lootbox_epoch) +RETURNS SETOF lootbox_counts_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + address, + COALESCE(tier1, 0), + COALESCE(tier2, 0), + COALESCE(tier3, 0), + COALESCE(tier4, 0), + COALESCE(tier5, 0) +FROM crosstab( + format( + 'SELECT + address, + reward_tier, + SUM(lootbox_count) + FROM lootbox + WHERE epoch = %s + GROUP BY + address, + reward_tier + ORDER BY 1', + quote_literal(epoch_) + ), + 'VALUES (1),(2),(3),(4),(5)' +) AS ct( + address VARCHAR, + tier1 NUMERIC, + tier2 NUMERIC, + tier3 NUMERIC, + tier4 NUMERIC, + tier5 NUMERIC +); +$$; + +--migrate:down + +DROP FUNCTION lootbox_counts; + +CREATE FUNCTION lootbox_counts() +RETURNS SETOF lootbox_counts_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + address, + COALESCE(tier1, 0), + COALESCE(tier2, 0), + COALESCE(tier3, 0), + COALESCE(tier4, 0), + COALESCE(tier5, 0) +FROM crosstab( + 'SELECT + address, + reward_tier, + SUM(lootbox_count) + FROM lootbox + GROUP BY + address, + reward_tier + ORDER BY 1', + 'VALUES (1),(2),(3),(4),(5)' +) AS ct( + address VARCHAR, + tier1 NUMERIC, + tier2 NUMERIC, + tier3 NUMERIC, + tier4 NUMERIC, + tier5 NUMERIC +); +$$; diff --git a/database/102-up-timescale/20240105003308-airdrop_leaderboard_add_epoch.sql b/database/102-up-timescale/20240105003308-airdrop_leaderboard_add_epoch.sql new file mode 100644 index 000000000..96a10036f --- /dev/null +++ b/database/102-up-timescale/20240105003308-airdrop_leaderboard_add_epoch.sql @@ -0,0 +1,72 @@ +-- migrate:up + +DROP FUNCTION airdrop_leaderboard; + +CREATE FUNCTION airdrop_leaderboard(epoch_ lootbox_epoch) +RETURNS SETOF airdrop_leaderboard_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + address, + -- placeholder + ROW_NUMBER() OVER () AS rank, + COUNT(DISTINCT referee) AS referral_count, + lb.total_box_count, + lb.highest_reward_tier, + COALESCE(liquidity.result, 1) AS liquidity_multiplier, + COALESCE(lootbox_amounts_rewarded_fusdc.amount_earned, 0), + COALESCE(lootbox_amounts_rewarded_arb.amount_earned, 0) +FROM ( + -- subquery to avoid re-summing lootbox_count for every referee + SELECT address, SUM(lootbox_count) as total_box_count, MAX(reward_tier) as highest_reward_tier + FROM lootbox + WHERE epoch = epoch_ + GROUP BY address +) lb + LEFT JOIN ( + SELECT amount_earned, recipient + FROM lootbox_amounts_rewarded + WHERE token_short_name = 'USDC' + ) AS lootbox_amounts_rewarded_fusdc ON lb.address = lootbox_amounts_rewarded_fusdc.recipient + LEFT JOIN ( + SELECT amount_earned, recipient + FROM lootbox_amounts_rewarded + WHERE token_short_name = 'ARB' + ) AS lootbox_amounts_rewarded_arb ON lb.address = lootbox_amounts_rewarded_arb.recipient + LEFT JOIN lootbox_referrals + ON lb.address = lootbox_referrals.referrer, + LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity +GROUP BY address, liquidity_multiplier, total_box_count, highest_reward_tier, lootbox_amounts_rewarded_fusdc.amount_earned, lootbox_amounts_rewarded_arb.amount_earned +$$; + +-- migrate:down + +DROP FUNCTION airdrop_leaderboard; + +CREATE FUNCTION airdrop_leaderboard() +RETURNS SETOF airdrop_leaderboard_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + address, + -- placeholder + ROW_NUMBER() OVER () AS rank, + COUNT(DISTINCT referee) AS referral_count, + lb.total_box_count, + lb.highest_reward_tier, + COALESCE(liquidity.result, 1) AS liquidity_multiplier +FROM ( + -- subquery to avoid re-summing lootbox_count for every referee + SELECT address, SUM(lootbox_count) as total_box_count, MAX(reward_tier) as highest_reward_tier + FROM lootbox + GROUP BY address +) lb + LEFT JOIN lootbox_referrals + ON lb.address = lootbox_referrals.referrer, + LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity +GROUP BY address, liquidity_multiplier, total_box_count, highest_reward_tier +$$; \ No newline at end of file diff --git a/web/app.fluidity.money/app/queries/addReferral.ts b/web/app.fluidity.money/app/queries/addReferral.ts index aaf284901..275640ec2 100644 --- a/web/app.fluidity.money/app/queries/addReferral.ts +++ b/web/app.fluidity.money/app/queries/addReferral.ts @@ -41,7 +41,7 @@ const addReferral = (referrer: string, referee: string) => { }; return jsonPost( - "https://fluidity.hasura.app/v1/graphql", + process.env.FLU_HASURA_URL!, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/addReferralCode.ts b/web/app.fluidity.money/app/queries/addReferralCode.ts index 0cccdca74..c544833c8 100644 --- a/web/app.fluidity.money/app/queries/addReferralCode.ts +++ b/web/app.fluidity.money/app/queries/addReferralCode.ts @@ -41,7 +41,7 @@ const addReferralCode = (address: string, code: string) => { }; return jsonPost( - "https://fluidity.hasura.app/v1/graphql", + process.env.FLU_HASURA_URL!, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts b/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts index 7435e468c..155de2069 100644 --- a/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts +++ b/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts @@ -2,7 +2,7 @@ import { jsonPost, gql, fetchInternalEndpoint } from "~/util"; const queryByUserAllTime = gql` query AirdropLeaderboard( - $epoch: String! + $epoch: lootbox_epoch! $address: String! ) { airdrop_leaderboard(where: { address: { _eq: $address } }, limit: 1) { @@ -18,7 +18,7 @@ const queryByUserAllTime = gql` const queryAllTime = gql` query AirdropLeaderboard( - $epoch: String! + $epoch: lootbox_epoch! ) { airdrop_leaderboard( args: { epoch_: $epoch } @@ -38,7 +38,7 @@ const queryAllTime = gql` const queryByUser24Hours = gql` query AirdropLeaderboard( - $epoch: String! + $epoch: lootbox_epoch! $address: String! ) { airdrop_leaderboard: airdrop_leaderboard_24_hours( @@ -79,7 +79,7 @@ const query24Hours = gql` const query24HoursByUserByApplication = gql` query AirdropLeaderboardApplication( - $epoch: String! + $epoch: lootbox_epoch! $application: ethereum_application! $address: String! ) { @@ -102,7 +102,7 @@ const query24HoursByUserByApplication = gql` const query24HoursByApplication = gql` query AirdropLeaderboardByApplication( - $epoch: String! + $epoch: lootbox_epoch! $application: ethereum_application! ) { airdrop_leaderboard: airdrop_leaderboard_24_hours_by_application( @@ -163,10 +163,11 @@ type AirdropLeaderboardResponse = { errors?: unknown; }; -export const useAirdropLeaderboardByUserAllTime = (address: string) => { +export const useAirdropLeaderboardByUserAllTime = (epoch: string, address: string) => { const { url, headers } = fetchInternalEndpoint(); const variables = { + epoch, address, }; const body = { @@ -181,10 +182,12 @@ export const useAirdropLeaderboardByUserAllTime = (address: string) => { ); }; -export const useAirdropLeaderboardAllTime = () => { +export const useAirdropLeaderboardAllTime = (epoch: string) => { const { url, headers } = fetchInternalEndpoint(); + const variables = { epoch }; const body = { query: queryAllTime, + variables, }; return jsonPost( @@ -194,11 +197,12 @@ export const useAirdropLeaderboardAllTime = () => { ); }; -export const useAirdropLeaderboardByUser24Hours = (address: string) => { +export const useAirdropLeaderboardByUser24Hours = (epoch: string, address: string) => { const { url, headers } = fetchInternalEndpoint(); const variables = { address, + epoch }; const body = { query: queryByUser24Hours, @@ -212,9 +216,11 @@ export const useAirdropLeaderboardByUser24Hours = (address: string) => { ); }; -export const useAirdropLeaderboard24Hours = () => { +export const useAirdropLeaderboard24Hours = (epoch: string) => { const { url, headers } = fetchInternalEndpoint(); + const variables = { epoch }; const body = { + variables, query: query24Hours, }; @@ -226,12 +232,14 @@ export const useAirdropLeaderboard24Hours = () => { }; export const useAirdropLeaderboardByUserByApplication24Hours = ( + epoch: string, address: string, application: string ) => { const { url, headers } = fetchInternalEndpoint(); const variables = { + epoch, address, application, }; @@ -247,10 +255,12 @@ export const useAirdropLeaderboardByUserByApplication24Hours = ( }; export const useAirdropLeaderboardByApplication24Hours = ( + epoch: string, application: string ) => { const { url, headers } = fetchInternalEndpoint(); const variables = { + epoch, application, }; const body = { diff --git a/web/app.fluidity.money/app/queries/useAirdropStats.ts b/web/app.fluidity.money/app/queries/useAirdropStats.ts index 25828ab32..b100db678 100644 --- a/web/app.fluidity.money/app/queries/useAirdropStats.ts +++ b/web/app.fluidity.money/app/queries/useAirdropStats.ts @@ -3,12 +3,15 @@ import { BottleTiers } from "~/routes/$network/query/dashboard/airdrop"; import { jsonPost, gql, fetchInternalEndpoint } from "~/util"; const queryAirdropStatsByAddress = gql` - query AirdropStats($address: String!, $now: timestamp!) { - lootboxCounts: lootbox_counts(where: { address: { _eq: $address } }) { + query AirdropStats($epoch: lootbox_epoch!, $address: String!, $now: timestamp!) { + lootboxCounts: lootbox_counts( + args: { epoch_: $epoch } + where: { address: { _eq: $address } } + ) { ${Rarity.Common}: tier1 ${Rarity.Uncommon}: tier2 ${Rarity.Rare}: tier3 - ${Rarity.UltraRare}: tier4 + ${Rarity.UltraRare}: tier4 ${Rarity.Legendary}: tier5 } liquidityMultiplier: calculate_a_y( @@ -26,11 +29,12 @@ const queryAirdropStatsByAddress = gql` } `; -export const useAirdropStatsByAddress = async (address: string) => { +export const useAirdropStatsByAddress = async (address: string, epoch: string) => { const { url, headers } = fetchInternalEndpoint(); const variables = { address, + epoch, now: new Date().toISOString(), }; const body = { diff --git a/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts b/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts index 30459d899..7e831752c 100644 --- a/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts @@ -41,7 +41,7 @@ const useApplicationRewardStatistics = async ( network: T | string ) => { const variables = { network }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { variables, query: query, diff --git a/web/app.fluidity.money/app/queries/useAssetStatistics.ts b/web/app.fluidity.money/app/queries/useAssetStatistics.ts index 11bd89fe2..887e7c889 100644 --- a/web/app.fluidity.money/app/queries/useAssetStatistics.ts +++ b/web/app.fluidity.money/app/queries/useAssetStatistics.ts @@ -86,7 +86,7 @@ const useAssetStatistics = ( }, }; - const fluGqlEndpoint = "https://fluidity.hasura.app/v1/graphql"; + const fluGqlEndpoint = process.env.FLU_HASURA_URL!; return jsonPost( fluGqlEndpoint, diff --git a/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts b/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts index 8dfd4e666..06345c435 100644 --- a/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts @@ -19,7 +19,7 @@ const query = gql` const useGlobalRewardStatistics = async (network: string) => { const variables = { network }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { variables, query: query, diff --git a/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts b/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts index 05d007bdf..d39a9150e 100644 --- a/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts @@ -76,7 +76,7 @@ const useHighestRewardStatisticsByNetwork = async (network: string) => { } const variables = { network }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { variables, query: queryByNetwork, @@ -102,7 +102,7 @@ type HighestRewardAllBody = { }; const useHighestRewardStatisticsAll = async () => { - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { query: queryAll, }; diff --git a/web/app.fluidity.money/app/queries/useLootBottles.ts b/web/app.fluidity.money/app/queries/useLootBottles.ts index f48ec6542..fabc36bef 100644 --- a/web/app.fluidity.money/app/queries/useLootBottles.ts +++ b/web/app.fluidity.money/app/queries/useLootBottles.ts @@ -42,7 +42,7 @@ const useLootboxesByTxHash = (filterHashes: string[]) => { }; return jsonPost( - "https://fluidity.hasura.app/v1/graphql", + process.env.FLU_HASURA_URL!, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useLootBottlesCount.ts b/web/app.fluidity.money/app/queries/useLootBottlesCount.ts index 60f1927c4..34c28658f 100644 --- a/web/app.fluidity.money/app/queries/useLootBottlesCount.ts +++ b/web/app.fluidity.money/app/queries/useLootBottlesCount.ts @@ -3,8 +3,11 @@ import { BottleTiers } from "~/routes/$network/query/dashboard/airdrop"; import { jsonPost, gql, fetchInternalEndpoint } from "~/util"; const QUERY_REFERRALS_BY_ADDRESS = gql` - query getReferralLootboxCountByAddress($address: String!) { - referralLootboxCounts: lootbox_referral_lootbottle_counts(where: { address: { _eq: $address } }) { + query getReferralLootboxCountByAddress($epoch: String!, $address: String!) { + referralLootboxCounts: lootbox_referral_lootbottle_counts( + args: { epoch_: $epoch } + where: { address: { _eq: $address } } + ) { ${Rarity.Common}: tier1 ${Rarity.Uncommon}: tier2 ${Rarity.Rare}: tier3 @@ -18,6 +21,7 @@ type ReferralLootboxCountBody = { query: string; variables: { address: string; + epoch: string; }; }; @@ -28,10 +32,11 @@ type ReferralLootboxCountRes = { errors?: unknown; }; -const useReferralLootboxesByAddress = (address: string) => { +const useReferralLootboxesByAddress = (epoch: string, address: string) => { const { url, headers } = fetchInternalEndpoint(); const variables = { + epoch, address, }; diff --git a/web/app.fluidity.money/app/queries/useLootboxConfig.ts b/web/app.fluidity.money/app/queries/useLootboxConfig.ts index 68a18f0e6..a3d7c98a4 100644 --- a/web/app.fluidity.money/app/queries/useLootboxConfig.ts +++ b/web/app.fluidity.money/app/queries/useLootboxConfig.ts @@ -1,13 +1,30 @@ import { BottleTiers } from "~/routes/$network/query/dashboard/airdrop"; import { jsonPost, gql, fetchInternalEndpoint } from "~/util"; -const queryGetConfig = gql` +const queryGetConfigCurrentProgram = gql` query getLootboxConfig { - lootboxConfig: lootbox_config(where: { is_current_program: { _eq: true }}) { - program_begin, - program_end, - epoch_identifier, - ethereum_application + lootboxConfig: lootbox_config( + where: { is_current_program: { _eq: true }} + limit: 1 + ) { + programBegin: program_begin, + programEnd: program_end, + epochIdentifier: epoch_identifier, + ethereumApplication: ethereum_application + } + } +`; + +const queryGetConfigSpecific = gql` + query getLootboxConfig($identifier: String!) { + lootboxConfig: lootbox_config( + where: { epoch_identifier: { _eq: $identifier }} + limit: 1 + ) { + programBegin: program_begin, + programEnd: program_end, + epochIdentifier: epoch_identifier, + ethereumApplication: ethereum_application } } `; @@ -16,22 +33,37 @@ type LootboxConfigBody = { query: string; }; +export type LootboxConfig = { + programBegin: string; + programEnd: string; + epochIdentifier: string; + ethereumApplication: string; + found: boolean; +}; + type LootboxConfigResponse = { data?: { - programBegin: Date; - programEnd: Date; - epochIdentifier: string; - ethereumApplication: string; + lootboxConfig: Array; }; errors?: unknown; }; -export const useLootboxConfig = () => { +type IUseLootboxConfig = { + identifier: string | undefined; + shouldFind: boolean | undefined; +}; + +export const useLootboxConfig = ({ identifier, shouldFind }: IUseLootboxConfig) => { const { url, headers } = fetchInternalEndpoint(); - const body = { - query: queryGetConfig, - }; + const body = (() => + shouldFind ? { + query: queryGetConfigCurrentProgram + } : { + query: queryGetConfigSpecific, + variables: { identifier } + } + )(); return jsonPost( url, diff --git a/web/app.fluidity.money/app/queries/useReferralCode.ts b/web/app.fluidity.money/app/queries/useReferralCode.ts index b6cd6c5d9..1b5019591 100644 --- a/web/app.fluidity.money/app/queries/useReferralCode.ts +++ b/web/app.fluidity.money/app/queries/useReferralCode.ts @@ -55,7 +55,7 @@ const useReferralCodeByAddress = (address: string) => { }; return jsonPost( - "https://fluidity.hasura.app/v1/graphql", + process.env.FLU_HASURA_URL!, body, process.env.FLU_HASURA_SECRET ? { @@ -76,7 +76,7 @@ const useReferralCodeByCode = (code: string) => { }; return jsonPost( - "https://fluidity.hasura.app/v1/graphql", + process.env.FLU_HASURA_URL!, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useReferralCount.ts b/web/app.fluidity.money/app/queries/useReferralCount.ts index aabd612b2..5ccb96994 100644 --- a/web/app.fluidity.money/app/queries/useReferralCount.ts +++ b/web/app.fluidity.money/app/queries/useReferralCount.ts @@ -65,7 +65,7 @@ const useActiveReferralCountByReferrerAddress = (address: string) => { }; return jsonPost( - "https://fluidity.hasura.app/v1/graphql", + process.env.FLU_HASURA_URL!, body, process.env.FLU_HASURA_SECRET ? { @@ -86,7 +86,7 @@ const useActiveReferralCountByRefereeAddress = (address: string) => { }; return jsonPost( - "https://fluidity.hasura.app/v1/graphql", + process.env.FLU_HASURA_URL!, body, process.env.FLU_HASURA_SECRET ? { @@ -107,7 +107,7 @@ const useInactiveReferralCountByRefereeAddress = (address: string) => { }; return jsonPost( - "https://fluidity.hasura.app/v1/graphql", + process.env.FLU_HASURA_URL!, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useReferrals.ts b/web/app.fluidity.money/app/queries/useReferrals.ts index 0da3ee93a..c1acd60d1 100644 --- a/web/app.fluidity.money/app/queries/useReferrals.ts +++ b/web/app.fluidity.money/app/queries/useReferrals.ts @@ -72,7 +72,7 @@ const useReferralByAddress = (referrer: string, referee: string) => { }; return jsonPost( - "https://fluidity.hasura.app/v1/graphql", + process.env.FLU_HASURA_URL!, body, process.env.FLU_HASURA_SECRET ? { @@ -93,7 +93,7 @@ const useInactiveReferralByAddress = (address: string) => { }; return jsonPost( - "https://fluidity.hasura.app/v1/graphql", + process.env.FLU_HASURA_URL!, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useStakingData.ts b/web/app.fluidity.money/app/queries/useStakingData.ts index 9d43759f1..0bc783fdb 100644 --- a/web/app.fluidity.money/app/queries/useStakingData.ts +++ b/web/app.fluidity.money/app/queries/useStakingData.ts @@ -24,7 +24,7 @@ export const useStakingDataByAddress = async ( address: `0x${"0".repeat(24)}${address.slice(2)}`, days_elapsed: daysElapsed, }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { variables, query: queryStakingDataByAddress, diff --git a/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts b/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts index ee371c37b..6429188e1 100644 --- a/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts @@ -42,7 +42,7 @@ const query = gql` const useTokenRewardStatistics = async (network: Chain | string) => { const variables = { network }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { variables, query: query, diff --git a/web/app.fluidity.money/app/queries/useTokens.ts b/web/app.fluidity.money/app/queries/useTokens.ts index 4dad1bd8f..b36d29cf3 100644 --- a/web/app.fluidity.money/app/queries/useTokens.ts +++ b/web/app.fluidity.money/app/queries/useTokens.ts @@ -26,7 +26,7 @@ export const useTokens = async () => { const { data: { asset }, } = await jsonPost( - "https://fluidity.hasura.app/v1/graphql", + process.env.FLU_HASURA_URL!, { query: tokenQuery }, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useUserRewards.ts b/web/app.fluidity.money/app/queries/useUserRewards.ts index 06654c913..96722797b 100644 --- a/web/app.fluidity.money/app/queries/useUserRewards.ts +++ b/web/app.fluidity.money/app/queries/useUserRewards.ts @@ -177,7 +177,7 @@ const useUserRewardsAll = async (network: string) => { const variables = { network, }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { variables, query: queryWinnersAll[network as Chain], @@ -196,7 +196,7 @@ const useUserRewardsAll = async (network: string) => { const useUserRewardsByAddress = async (network: string, address: string) => { const variables = { network, address }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { variables, query: queryWinnersByAddress[network as Chain], @@ -217,7 +217,7 @@ const useUserPendingRewardsAll = async (network: string) => { const variables = { network, }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { variables, query: queryPendingWinnersAll, @@ -239,7 +239,7 @@ const useUserPendingRewardsByAddress = async ( address: string ) => { const variables = { network, address }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { variables, query: queryPendingWinnersByAddress, diff --git a/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts b/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts index d7152d5ce..a50ddd937 100644 --- a/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts +++ b/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts @@ -82,7 +82,7 @@ const useUserUnclaimedRewards = async (network: string, address: string) => { }, }; - const fluGqlEndpoint = "https://fluidity.hasura.app/v1/graphql"; + const fluGqlEndpoint = process.env.FLU_HASURA_URL!; return jsonPost( fluGqlEndpoint, diff --git a/web/app.fluidity.money/app/queries/useUserYield.ts b/web/app.fluidity.money/app/queries/useUserYield.ts index 5a6b590ce..b3b09f556 100644 --- a/web/app.fluidity.money/app/queries/useUserYield.ts +++ b/web/app.fluidity.money/app/queries/useUserYield.ts @@ -95,7 +95,7 @@ type UserYieldByAddressBody = { const useUserYieldAll = async (network: string) => { const variables = { network }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { variables, query: queryAll, @@ -114,7 +114,7 @@ const useUserYieldAll = async (network: string) => { const useUserYieldByAddress = async (network: string, address: string) => { const variables = { network, address }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; const body = { variables, query: queryByAddress, diff --git a/web/app.fluidity.money/app/queries/useVolumeStats.ts b/web/app.fluidity.money/app/queries/useVolumeStats.ts index ebe29e72d..b799aa0e4 100644 --- a/web/app.fluidity.money/app/queries/useVolumeStats.ts +++ b/web/app.fluidity.money/app/queries/useVolumeStats.ts @@ -120,7 +120,7 @@ const useVolumeStatsByAddress = async (network: string, address: string) => { query: queryVolumeByAddress, }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; return await jsonPost( url, @@ -143,7 +143,7 @@ const useVolumeStats = async (network: string) => { query: queryVolume, }; - const url = "https://fluidity.hasura.app/v1/graphql"; + const url = process.env.FLU_HASURA_URL!; return await jsonPost( url, diff --git a/web/app.fluidity.money/app/routes/$network/dashboard.tsx b/web/app.fluidity.money/app/routes/$network/dashboard.tsx index 80dec9167..fdf562c2b 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard.tsx @@ -495,19 +495,17 @@ export default function Dashboard() { )} {/* Accept Referral Modal */} - {false && ( - setAcceptReferralModalVisibility(false)} - > - - - )} + setAcceptReferralModalVisibility(false)} + > + + {/* Fluidify Money button, in a portal with z-index above tooltip if another modal isn't open */} @@ -679,36 +677,32 @@ export default function Dashboard() { {/* Referrals Button */} - {false && ( - { - width < airdropMobileBreakpoint - ? navigate(`/${network}/dashboard/airdrop#referrals`) - : setReferralModalVisibility(true); - }} - icon={} - > - {isMobile ? "" : "Referral"} - - )} + { + width < airdropMobileBreakpoint + ? navigate(`/${network}/dashboard/airdrop#referrals`) + : setReferralModalVisibility(true); + }} + icon={} + > + {isMobile ? "" : "Referral"} + {/* Fluidify button */} - {otherModalOpen && showExperiment("Fluidify-Button-Placement") && ( - { - client?.track("user", "click_fluidify"); - navigate(`/${network}/fluidify`); - }} - > - Fluidify{isMobile ? "" : " Money"} - - )} + { + client?.track("user", "click_fluidify"); + navigate(`/${network}/fluidify`); + }} + > + Fluidify{isMobile ? "" : " Money"} + {/* Prize Money */} { export const loader: LoaderFunction = async ({ params }) => { const network = params.network ?? ""; - const epochDays = dayDifference(new Date(), EPOCH_START_DATE); - // Staking Tokens const allowedTokenSymbols = new Set(["fUSDC", "USDC", "wETH"]); const { tokens } = config.config[network]; @@ -100,16 +96,12 @@ export const loader: LoaderFunction = async ({ params }) => { return json({ tokens: allowedTokens, - epochDaysTotal: EPOCH_DAYS_TOTAL, - epochDays, network, } satisfies LoaderData); }; type LoaderData = { tokens: Array; - epochDaysTotal: number; - epochDays: number; network: string; }; @@ -124,10 +116,16 @@ const SAFE_DEFAULT_AIRDROP: AirdropLoaderData = { }, bottlesCount: 0, liquidityMultiplier: 0, - stakes: [], wethPrice: 0, usdcPrice: 0, - loaded: false, + programBegin: new Date("2023-05-01T12:00:00+02:00"), + programEnd: new Date("2023-06-28 T12:00:00+02:00"), + epochDaysTotal: 30, + epochDaysElapsed: 30, + epochIdentifier: "epoch_1", + ethereumApplication: "none", + epochFound: false, + loaded: false }; const SAFE_DEFAULT_AIRDROP_LEADERBOARD: AirdropLeaderboardLoaderData = { @@ -164,23 +162,8 @@ const GLOBAL_AIRDROP_BOTTLE_TIERS = { [Rarity.Legendary]: 5, }; -// defaults lifted from database/20231219094456-lootbox_config_add_prev_epoch.sql -const LOOTBOX_CONFIG_DEFAULT: LootboxConfig = { - found: false, - programBegin: new Date("2023-05-01T12:00:00+02:00"), - programEnd: new Date("2023-06-28 T12:00:00+02:00"), - epochIdentifier: "epoch_1", - ethereumApplication: "none", - loaded: false -}; - const Airdrop = () => { - const { - epochDaysTotal, - epochDays, - tokens: defaultTokens, - network, - } = useLoaderData(); + const { tokens: defaultTokens, network } = useLoaderData(); if (network !== "arbitrum") { return ( @@ -227,20 +210,26 @@ const Airdrop = () => { redeemTokens, } = useContext(FluidityFacadeContext); - const { data: lootboxConfig } = useCache( - `/${network}/query/lootboxConfig` - ); + const { width } = useViewport(); + + const navigate = useNavigate(); + + const mobileBreakpoint = 768; + + const isMobile = width < mobileBreakpoint; const { data: airdropData } = useCache( - address ? `/${network}/query/dashboard/airdrop?address=${address}` : "" + address ? `/${network}/query/dashboard/airdrop?address=${address}&epoch=${EPOCH_CURRENT_IDENTIFIER}` : "" ); + console.log("airdropData", airdropData); + const { data: airdropLeaderboardData } = useCache( `/${network}/query/dashboard/airdropLeaderboard?period=${ leaderboardFilterIndex === 0 ? "24" : "all" }&address=${address ?? ""}${ - leaderboardFilterIndex === 0 ? "&provider=kyber_classic" : "" - }` + leaderboardFilterIndex === 0 ? "&provider=${currentApplication}" : "" + }&epoch=${EPOCH_CURRENT_IDENTIFIER}` ); const { data: referralData } = useCache( @@ -252,14 +241,6 @@ const Airdrop = () => { address ? `/${network}/query/referralBottles?address=${address}` : "" ); - const { width } = useViewport(); - - const navigate = useNavigate(); - - const mobileBreakpoint = 768; - - const isMobile = width < mobileBreakpoint; - const data = { airdrop: { ...SAFE_DEFAULT_AIRDROP, @@ -286,6 +267,13 @@ const Airdrop = () => { bottlesCount, wethPrice, usdcPrice, + programBegin, + programEnd, + epochDaysTotal, + epochDaysElapsed, + epochIdentifier, + ethereumApplication, + epochFound, }, referrals: { numActiveReferreeReferrals, @@ -326,11 +314,6 @@ const Airdrop = () => { }> >([]); - const fetchUserStakes = async (address: string) => { - const stakingDeposits = (await getStakingDeposits?.(address)) ?? []; - setStakes(stakingDeposits); - }; - const fetchUserTokenBalance = async () => { const userTokenBalance = await Promise.all( tokens.map(async ({ address }) => (await balance?.(address)) || new BN(0)) @@ -407,8 +390,6 @@ const Airdrop = () => { fetchUserTokenBalance(); - fetchUserStakes(address); - fetchUserRedeemableTokens(address); }, [address]); @@ -419,7 +400,6 @@ const Airdrop = () => { const res = await (await redeemTokens?.())?.confirmTx(); fetchUserTokenBalance(); - fetchUserStakes(address); fetchUserRedeemableTokens(address); return res; @@ -684,7 +664,7 @@ const Airdrop = () => { seeBottlesDetails={() => setCurrentModal("bottles-details")} seeLeaderboardMobile={() => setCurrentModal("leaderboard")} epochMax={epochDaysTotal} - epochDays={epochDays} + epochDays={epochDaysElapsed} activatedReferrals={numActiveReferrerReferrals} totalBottles={bottlesCount} network={network} @@ -770,7 +750,6 @@ const Airdrop = () => { wethPrice={wethPrice} usdcPrice={usdcPrice} stakeCallback={() => { - fetchUserStakes(address ?? ""); fetchUserTokenBalance(); }} /> @@ -872,7 +851,6 @@ const Airdrop = () => { usdcPrice={usdcPrice} isMobile={isMobile} stakeCallback={() => { - fetchUserStakes(address ?? ""); fetchUserTokenBalance(); }} /> @@ -997,7 +975,7 @@ const Airdrop = () => { seeBottlesDetails={() => setCurrentModal("bottles-details")} seeLeaderboardMobile={() => setCurrentModal("leaderboard")} epochMax={epochDaysTotal} - epochDays={epochDays} + epochDays={epochDaysElapsed} activatedReferrals={numActiveReferrerReferrals} totalBottles={bottlesCount} network={network} @@ -1453,7 +1431,7 @@ const airdropRankRow = ( ); - case "FUSDC EARNED": + case "$fUSDC EARNED": return ( - {toSignificantDecimals(fusdcEarned, 0)}x + {fusdcEarned} ); - case "ARB EARNED": + case "$ARB EARNED": return ( - {toSignificantDecimals(arbEarned, 0)}x + {arbEarned} ); diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx index f4add9655..4bea10b10 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx @@ -262,6 +262,7 @@ export default function Home() { { name: "VALUE" }, { name: "FLUID REWARDS", show: width >= 500 }, { name: "$UTILITY REWARDS", show: width >= 500 }, + { name: "BOTTLES EARNED", show: width >= 500 }, { name: "ACCOUNT", show: width >= 375 }, { name: "TIME", show: width >= 850, alignRight: true }, ]; @@ -454,12 +455,29 @@ export default function Home() { )} ); + case "BOTTLES EARNED": + return ( + { bottlesEarned ? ( + + + {bottlesEarned} + + + ) : ( + - + ) + } + ) case "ACCOUNT": return ( {sender === MintAddress diff --git a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx index c46ae93df..3d610a5f7 100644 --- a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx @@ -5,6 +5,7 @@ import { LoaderFunction, json } from "@remix-run/node"; import { captureException } from "@sentry/react"; import { useAirdropStatsByAddress } from "~/queries/useAirdropStats"; import { useStakingDataByAddress } from "~/queries/useStakingData"; +import { useLootboxConfig } from "~/queries"; import { getWethUsdPrice } from "~/util/chainUtils/ethereum/transaction"; import EACAggregatorProxyAbi from "~/util/chainUtils/ethereum/EACAggregatorProxy.json"; import config from "~/webapp.config.server"; @@ -29,17 +30,19 @@ export type AirdropLoaderData = { bottleTiers: BottleTiers; bottlesCount: number; liquidityMultiplier: number; - stakes: Array; wethPrice: number; usdcPrice: number; - loaded: boolean; referralCode?: string; + programBegin: Date; + programEnd: Date; + epochDaysTotal: number; + epochDaysElapsed: number; + epochIdentifier: string; + ethereumApplication: string; + epochFound: boolean; + loaded: boolean; }; -const EPOCH_DAYS_TOTAL = 31; -// temp: april 19th, 2023 -const EPOCH_START_DATE = new Date(2023, 3, 20); - const MAINNET_ID = 0; const dayDifference = (date1: Date, date2: Date) => @@ -50,13 +53,54 @@ export const loader: LoaderFunction = async ({ params, request }) => { const url = new URL(request.url); const address_ = url.searchParams.get("address"); + const epochIdentifier = url.searchParams.get("epoch"); const address = address_?.toLowerCase(); - if (!address || !network) throw new Error("Invalid Request"); + if (!address || !network || !epochIdentifier) throw new Error("Invalid Request"); + + const { data, errors } = await useLootboxConfig({ + identifier: epochIdentifier!, + shouldFind: false + }); + + if (errors) { + captureException(errors, { + tags: { + section: "airdrop", + }, + }); + + return new Error("Server could not fulfill request"); + } + + if (!data) { + // return defaults + return null; + } + + const { lootboxConfig: configs } = data; + + // if we didn't find anything, then we need to return the defaults + + if (configs.length != 1) { + return null; + } - const daysElapsed = - dayDifference(new Date(), EPOCH_START_DATE) % EPOCH_DAYS_TOTAL; + const { + programBegin: programBegin_, + programEnd: programEnd_, + ethereumApplication, + found: epochFound + } = configs[0]; + + const programBegin = new Date(programBegin_); + const programEnd = new Date(programEnd_); + + const epochDaysTotal = Math.round((programEnd.valueOf() - programBegin.valueOf()) / (1000 * 60 * 60 * 24)); + + const epochDaysElapsed = + dayDifference(new Date(), programBegin) % epochDaysTotal; const infuraRpc = config.drivers[network][MAINNET_ID].rpc.http; const provider = new JsonRpcProvider(infuraRpc); @@ -64,19 +108,18 @@ export const loader: LoaderFunction = async ({ params, request }) => { const eacAggregatorProxyAddr = config.contract.eac_aggregator_proxy[network as Chain]; + console.log("aaaa"); + try { const [ { data: airdropStatsData, errors: airdropStatsErrors }, - { data: stakingData, errors: stakingErrors }, wethPrice, ] = await Promise.all([ - useAirdropStatsByAddress(address), - useStakingDataByAddress(address, daysElapsed), + useAirdropStatsByAddress(address, epochIdentifier), getWethUsdPrice(provider, eacAggregatorProxyAddr, EACAggregatorProxyAbi), ]); if (airdropStatsErrors || !airdropStatsData) throw airdropStatsErrors; - if (stakingErrors || !stakingData) throw stakingErrors; const { lootboxCounts: [bottleTiers_], @@ -86,15 +129,6 @@ export const loader: LoaderFunction = async ({ params, request }) => { }, } = airdropStatsData; - const stakes = stakingData.stakes.map( - ({ multiplier, durationSecs, amount, ...stake }) => ({ - ...stake, - amountUsd: amount / 1e6, - durationDays: durationSecs / 60 / 60 / 24, - multiplier: multiplier[0].result, - }) - ); - const bottleTiers = bottleTiers_ || { [Rarity.Common]: 0, [Rarity.Uncommon]: 0, @@ -111,10 +145,16 @@ export const loader: LoaderFunction = async ({ params, request }) => { (sum: number, quantity: number) => sum + quantity, 0 ), - stakes, wethPrice, usdcPrice: 1, loaded: true, + programBegin, + programEnd, + epochDaysTotal, + epochDaysElapsed, + epochIdentifier, + epochFound, + ethereumApplication } satisfies AirdropLoaderData); } catch (err) { captureException(new Error(`Could not fetch airdrop data: ${err}`), { @@ -122,6 +162,7 @@ export const loader: LoaderFunction = async ({ params, request }) => { section: "network/index", }, }); + console.log("ccccc", err); return new Error("Server could not fulfill request"); } }; diff --git a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx index 293c8f1a7..322fbf201 100644 --- a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx @@ -22,6 +22,11 @@ export const loader: LoaderFunction = async ({ params, request }) => { const { network } = params; const url = new URL(request.url); + + const epoch = url.searchParams.get("epoch"); + + if (!epoch) throw new Error("Invalid Request"); + const address = url.searchParams.get("address") ?? ""; const period = url.searchParams.get("period") ?? ""; const provider_ = url.searchParams.get("provider") ?? ""; @@ -38,15 +43,16 @@ export const loader: LoaderFunction = async ({ params, request }) => { switch (true) { case useAll: { return [ - useAirdropLeaderboardAllTime, - useAirdropLeaderboardByUserAllTime, + () => useAirdropLeaderboardAllTime(epoch), + (address: string) => useAirdropLeaderboardByUserAllTime(epoch, address), ]; } case use24Hours && !!provider: { return [ - () => useAirdropLeaderboardByApplication24Hours(provider), + () => useAirdropLeaderboardByApplication24Hours(epoch, provider), (address: string) => useAirdropLeaderboardByUserByApplication24Hours( + epoch, address, provider ), @@ -55,15 +61,14 @@ export const loader: LoaderFunction = async ({ params, request }) => { case use24Hours && !provider: default: { return [ - useAirdropLeaderboard24Hours, - useAirdropLeaderboardByUser24Hours, + () => useAirdropLeaderboard24Hours(epoch), + (address: string) => useAirdropLeaderboardByUser24Hours(epoch, address), ]; } } })(); - const { data: globalLeaderboardData, errors: globalLeaderboardErrors } = - await useAllQuery(); + const { data: globalLeaderboardData, errors: globalLeaderboardErrors } = await useAllQuery(); if (!globalLeaderboardData || globalLeaderboardErrors) throw globalLeaderboardErrors; diff --git a/web/app.fluidity.money/app/routes/$network/query/lootboxConfig.tsx b/web/app.fluidity.money/app/routes/$network/query/lootboxConfig.tsx deleted file mode 100644 index 092bffa9b..000000000 --- a/web/app.fluidity.money/app/routes/$network/query/lootboxConfig.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import { LoaderFunction, json } from "@remix-run/node"; -import { captureException } from "@sentry/react"; -import config from "~/webapp.config.server"; -import { useLootboxConfig } from "~/queries"; - -export type LootboxConfig = { - found: boolean; - programBegin: Date; - programEnd: Date; - epochIdentifier: string; - ethereumApplication: string; - loaded: boolean; -}; - -export const loader: LoaderFunction = async ({ params, request }) => { - const { network } = params; - - const url = new URL(request.url); - - try { - const { data, errors } = await useLootboxConfig(); - - if (errors || !data) { - captureException(errors, { - tags: { - section: "airdrop", - }, - }); - - return new Error("Server could not fulfill request"); - } - - const { programBegin, programEnd, epochIdentifier, ethereumApplication } = data; - - return json({ - found: true, - programBegin, - programEnd, - epochIdentifier, - ethereumApplication, - loaded: true, - } satisfies LootboxConfig); - } catch (err) { - captureException(new Error(`Could not fetch lootbox config: ${err}`), { - tags: { - section: "network/index", - }, - }); - return new Error("Server could not fulfill request"); - } -}; diff --git a/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx b/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx index 07a50c3b0..2b11f29f4 100644 --- a/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx @@ -15,15 +15,17 @@ export const loader: LoaderFunction = async ({ request }) => { const url = new URL(request.url); const address_ = url.searchParams.get("address") ?? ""; + const epoch = url.searchParams.get("epoch"); const address = address_.toLocaleLowerCase(); - if (!address) { + if (!address || !epoch) throw new Error("Invalid Request"); - } const { data: referralBottleCountData, errors: referralBottleCountErr } = - await useReferralLootboxesByAddress(address); + await useReferralLootboxesByAddress(epoch, address); + + console.log("errors", referralBottleCountErr); if (referralBottleCountErr || !referralBottleCountData) { throw new Error("Could not fetch Referral Bottles"); diff --git a/web/app.fluidity.money/app/styles/dashboard.css b/web/app.fluidity.money/app/styles/dashboard.css index ede067258..443d14bf4 100644 --- a/web/app.fluidity.money/app/styles/dashboard.css +++ b/web/app.fluidity.money/app/styles/dashboard.css @@ -917,4 +917,9 @@ ul.sidebar-nav li div.active { stroke: currentColor; } +.fluidify-button-dashboard { + background-color: white; + color: black; +} + /*# sourceMappingURL=dashboard.css.map */ diff --git a/web/app.fluidity.money/app/styles/dashboard.scss b/web/app.fluidity.money/app/styles/dashboard.scss index f143136b5..423e58c21 100644 --- a/web/app.fluidity.money/app/styles/dashboard.scss +++ b/web/app.fluidity.money/app/styles/dashboard.scss @@ -1007,3 +1007,8 @@ ul.sidebar-nav { } } } + +.fluidify-button-dashboard { + background-color: white; + color: black; +} diff --git a/web/app.fluidity.money/app/util/api/graphql.ts b/web/app.fluidity.money/app/util/api/graphql.ts index 59a11e4ea..3636e33b8 100644 --- a/web/app.fluidity.money/app/util/api/graphql.ts +++ b/web/app.fluidity.money/app/util/api/graphql.ts @@ -11,6 +11,8 @@ type GqlEndpoint = { type GqlBackend = "hasura"; +const HasuraUrl = "http://localhost:8080/v1/graphql"; + export const networkGqlBackend = (network: string): GqlBackend | null => { switch (network) { case "solana": @@ -26,7 +28,7 @@ export const fetchGqlEndpoint = (network: string): GqlEndpoint | null => { switch (networkGqlBackend(network)) { case "hasura": return { - url: "https://fluidity.hasura.app/v1/graphql", + url: HasuraUrl, headers: { "x-hasura-admin-secret": process.env.FLU_HASURA_SECRET ?? "", }, @@ -37,7 +39,7 @@ export const fetchGqlEndpoint = (network: string): GqlEndpoint | null => { }; export const fetchInternalEndpoint = (): GqlEndpoint => ({ - url: "https://fluidity.hasura.app/v1/graphql", + url: HasuraUrl, headers: typeof process.env.FLU_HASURA_SECRET === "string" ? { diff --git a/web/app.fluidity.money/app/util/chainUtils/ethereum/transaction.ts b/web/app.fluidity.money/app/util/chainUtils/ethereum/transaction.ts index 545721d1d..428a89178 100644 --- a/web/app.fluidity.money/app/util/chainUtils/ethereum/transaction.ts +++ b/web/app.fluidity.money/app/util/chainUtils/ethereum/transaction.ts @@ -628,10 +628,10 @@ export const handleContractErrors = async ( if (metaMaskError?.value.code === -32603) { throw new Error( - `Failed to make swap. Please reset your Metamask account (settings -> advanced -> reset account)` + `RPC error. Please reset your Metamask account (settings -> advanced -> reset account)` ); } else if (metaMaskError?.value.code === -32000) { - throw new Error(`Failed to make swap. Gas limit too low.`); + throw new Error(`RPC error. Gas limit too low.`); } // otherwise, check for a 'non intrinsic' gas error (gas exhausted) @@ -640,12 +640,12 @@ export const handleContractErrors = async ( // found revert opcode, assume it's a gas error since we can't call this with an insufficient balance within the application if (receipt?.status === 0) { throw new Error( - `Failed to make swap. Gas limit of ${receipt?.gasUsed?.toNumber()} exhausted!` + `RPC error. Gas limit of ${receipt?.gasUsed?.toNumber()} exhausted!` ); } } catch (e) { // otherwise, use a generic error - throw new Error(`Failed to make swap. ${msg}`); + throw new Error(`RPC error. ${msg}`); } }; diff --git a/web/app.fluidity.money/contexts/LootboxProvider.tsx b/web/app.fluidity.money/contexts/LootboxProvider.tsx deleted file mode 100644 index e0256773b..000000000 --- a/web/app.fluidity.money/contexts/LootboxProvider.tsx +++ /dev/null @@ -1,22 +0,0 @@ - -import { createContext } from "react"; - -type LootboxType = { - epochName: string -}; - -const LootboxContext = createContext({ epochName: "" }); - -interface ILootboxProviderProps { - children: React.ReactNode; -} - -const LootboxProvider = ({ children }: ILootboxProviderProps) => { - return ( - <> - - - ); -}; - -export default LootboxProvider; From 6f8db636a0459f9b6945a4aa18e5dde243c69017 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 8 Jan 2024 12:03:55 +1030 Subject: [PATCH 07/18] Add function for returning lootbottles alongside user actions --- ...r_actions_add_user_actions_lootbottles.sql | 64 +++++++++++++++++++ .../app/queries/useLootboxConfig.ts | 2 +- .../$network/dashboard/airdrop/index.tsx | 25 ++++---- .../$network/query/dashboard/airdrop.tsx | 3 +- .../$network/query/dashboard/prizePool.tsx | 1 + .../routes/arbitrum/query/dashboard/home.tsx | 4 +- .../app/styles/dashboard/airdrop.css | 4 ++ .../app/styles/dashboard/airdrop.scss | 4 ++ 8 files changed, 90 insertions(+), 17 deletions(-) create mode 100644 database/102-up-timescale/20240108102606-user_actions_add_user_actions_lootbottles.sql diff --git a/database/102-up-timescale/20240108102606-user_actions_add_user_actions_lootbottles.sql b/database/102-up-timescale/20240108102606-user_actions_add_user_actions_lootbottles.sql new file mode 100644 index 000000000..706c80065 --- /dev/null +++ b/database/102-up-timescale/20240108102606-user_actions_add_user_actions_lootbottles.sql @@ -0,0 +1,64 @@ +-- migrate:up + +-- this is a copy of user_actions + +CREATE TABLE user_actions_lootbottles_return ( + event_number BIGINT NOT NULL, + network network_blockchain NOT NULL, + type user_action NOT NULL, + swap_in BOOLEAN, + sender_address VARCHAR NOT NULL, + recipient_address VARCHAR, + amount uint256 NOT NULL, + time TIMESTAMP NOT NULL, + transaction_hash VARCHAR NOT NULL, + token_short_name VARCHAR NOT NULL, + token_decimals INTEGER NOT NULL, + solana_sender_owner_address VARCHAR NOT NULL, + solana_recipient_owner_address VARCHAR NOT NULL, + log_index BIGINT NOT NULL, + amount_str VARCHAR NOT NULL, + application VARCHAR NOT NULL, + + -- extra sections for the lootbottles + reward_tier INTEGER, + lootbox_count NUMERIC +); + +CREATE FUNCTION user_actions_lootbottles() +RETURNS SETOF user_actions_lootbottles_return +LANGUAGE SQL +STABLE +AS +$$ +SELECT + event_number, + network network_blockchain, + type user_action, + swap_in, + sender_address, + recipient_address, + amount, + time, + transaction_hash, + token_short_name, + token_decimals, + solana_sender_owner_address, + solana_recipient_owner_address, + log_index, + amount_str, + application, + lootbox_user_actions.reward_tier, + lootbox_user_actions.lootbox_count +FROM + user_actions +LEFT JOIN ( + SELECT reward_tier, lootbox_count FROM lootbox +) AS lootbox_user_actions ON transaction_hash = user_actions.transaction_hash +$$; + +-- migrate:down + +DROP TABLE user_actions_lootbottles_return; + +DROP FUNCTION user_actions_lootbottles; diff --git a/web/app.fluidity.money/app/queries/useLootboxConfig.ts b/web/app.fluidity.money/app/queries/useLootboxConfig.ts index a3d7c98a4..1b619055c 100644 --- a/web/app.fluidity.money/app/queries/useLootboxConfig.ts +++ b/web/app.fluidity.money/app/queries/useLootboxConfig.ts @@ -16,7 +16,7 @@ const queryGetConfigCurrentProgram = gql` `; const queryGetConfigSpecific = gql` - query getLootboxConfig($identifier: String!) { + query getLootboxConfig($identifier: lootbox_epoch!) { lootboxConfig: lootbox_config( where: { epoch_identifier: { _eq: $identifier }} limit: 1 diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx index c87d4834a..8b3408737 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx @@ -233,12 +233,12 @@ const Airdrop = () => { ); const { data: referralData } = useCache( - address ? `/${network}/query/referrals?address=${address}` : "" + address ? `/${network}/query/referrals?address=${address}&epoch=${EPOCH_CURRENT_IDENTIFIER}` : "" ); const { data: referralLootboxData } = useCache( - address ? `/${network}/query/referralBottles?address=${address}` : "" + address ? `/${network}/query/referralBottles?address=${address}&epoch=${EPOCH_CURRENT_IDENTIFIER}` : "" ); const data = { @@ -522,14 +522,14 @@ const Airdrop = () => { > Airdrop Dashboard - {/* setCurrentModal("tutorial")} groupId="airdrop" isSelected={isMobile && currentModal === "tutorial"} > Airdrop Tutorial - */} + { @@ -552,7 +552,7 @@ const Airdrop = () => { > Leaderboard - {/* setCurrentModal("referrals")} groupId="airdrop" @@ -562,22 +562,21 @@ const Airdrop = () => { setCurrentModal("stake")} + onClick={() => setCurrentModal("testnet-rewards")} groupId="airdrop" - isSelected={isMobile && currentModal === "stake"} + isSelected={isMobile && currentModal === "testnet-rewards"} disabled={true} > - Stake + Testnet Rewards setCurrentModal("testnet-rewards")} groupId="airdrop" - isSelected={isMobile && currentModal === "testnet-rewards"} - disabled={true} > - Testnet Rewards - */} + + Dune + +
); }; diff --git a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx index 3d610a5f7..960da8fbe 100644 --- a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx @@ -65,6 +65,7 @@ export const loader: LoaderFunction = async ({ params, request }) => { }); if (errors) { + console.log("errors", errors); captureException(errors, { tags: { section: "airdrop", @@ -108,8 +109,6 @@ export const loader: LoaderFunction = async ({ params, request }) => { const eacAggregatorProxyAddr = config.contract.eac_aggregator_proxy[network as Chain]; - console.log("aaaa"); - try { const [ { data: airdropStatsData, errors: airdropStatsErrors }, diff --git a/web/app.fluidity.money/app/routes/$network/query/dashboard/prizePool.tsx b/web/app.fluidity.money/app/routes/$network/query/dashboard/prizePool.tsx index 182786e8d..30fcbda26 100644 --- a/web/app.fluidity.money/app/routes/$network/query/dashboard/prizePool.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/dashboard/prizePool.tsx @@ -25,6 +25,7 @@ export async function loader() { }, ].map(({ network, abi, getPrizePool }) => { const infuraRpc = config.drivers[network][mainnetId].rpc.http; + console.log("infura rpc", infuraRpc); const provider = new JsonRpcProvider(infuraRpc); const rewardPoolAddr = config.contract.prize_pool[network as Chain]; diff --git a/web/app.fluidity.money/app/routes/arbitrum/query/dashboard/home.tsx b/web/app.fluidity.money/app/routes/arbitrum/query/dashboard/home.tsx index f7e2b4375..6d7d10076 100644 --- a/web/app.fluidity.money/app/routes/arbitrum/query/dashboard/home.tsx +++ b/web/app.fluidity.money/app/routes/arbitrum/query/dashboard/home.tsx @@ -49,10 +49,12 @@ export const loader: LoaderFunction = async ({ request }) => { } if (rewardsErr || !rewardsData) { - throw new Error("Could not fetch rewards data"); + console.log("Could not fetch rewards data", rewardsErr); + throw new Error(`Could not fetch rewards data: ${rewardsErr}`); } if (graphErr || !graphData) { + console.log("Could not fetch graph data", graphErr); throw new Error("Could not fetch graph data"); } diff --git a/web/app.fluidity.money/app/styles/dashboard/airdrop.css b/web/app.fluidity.money/app/styles/dashboard/airdrop.css index fb841c4bf..17dbfcf01 100644 --- a/web/app.fluidity.money/app/styles/dashboard/airdrop.css +++ b/web/app.fluidity.money/app/styles/dashboard/airdrop.css @@ -923,4 +923,8 @@ aspect-ratio: 1/1; } +#tutorial, #staking-stats, #bottles-details, #testnet-rewards { + position: fixed; +} + /*# sourceMappingURL=airdrop.css.map */ diff --git a/web/app.fluidity.money/app/styles/dashboard/airdrop.scss b/web/app.fluidity.money/app/styles/dashboard/airdrop.scss index 532b157c9..3be824138 100644 --- a/web/app.fluidity.money/app/styles/dashboard/airdrop.scss +++ b/web/app.fluidity.money/app/styles/dashboard/airdrop.scss @@ -1060,3 +1060,7 @@ $holo: linear-gradient( } } } + +#tutorial, #staking-stats, #bottles-details, #testnet-rewards { + position: fixed; +} From d07d6d82677fa65a0770f8a2e0bb40dc41e77a6c Mon Sep 17 00:00:00 2001 From: user Date: Mon, 8 Jan 2024 19:58:39 +1030 Subject: [PATCH 08/18] Fix presentation of lootbox amounts that are tracked using the rewards --- .../app/routes/$network/dashboard/home.tsx | 5 +---- .../$network/dashboard/rewards/index.tsx | 22 +++++++++++++++++++ .../$network/query/dashboard/rewards.tsx | 1 + 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx index 89e660f70..f592a5c18 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx @@ -465,13 +465,10 @@ export default function Home() { className="table-address" href={`/${network}/dashboard/airdrop`} > - - {lootboxCount} - ) : ( diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/rewards/index.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/rewards/index.tsx index 64f00566d..cfd57d002 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/rewards/index.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/rewards/index.tsx @@ -38,6 +38,7 @@ import { WalletIcon, TabButton, toDecimalPlaces, + LootBottle } from "@fluidity-money/surfing"; import { useContext, useEffect, useState, useMemo } from "react"; import { ToolTipContent, useToolTip, UtilityToken } from "~/components"; @@ -257,6 +258,7 @@ export default function Rewards() { { name: "VALUE" }, { name: "FLUID REWARDS", show: width >= 500 }, { name: "$UTILITY REWARDS", show: width >= 500 }, + { name: "BOTTLES EARNED", show: width >= 500 }, { name: "WINNER", show: width >= 850 }, { name: "REWARDED TIME", show: width >= 850, alignRight: true }, ]; @@ -432,6 +434,8 @@ export default function Rewards() { currency, utilityTokens, application, + lootboxCount, + rewardTier } = data; const toolTip = useToolTip(); @@ -537,6 +541,24 @@ export default function Rewards() { )} ); + case "BOTTLES EARNED": + return ( + { lootboxCount ? ( + + + + ) : ( + - + ) + } + ); case "WINNER": return ( diff --git a/web/app.fluidity.money/app/routes/$network/query/dashboard/rewards.tsx b/web/app.fluidity.money/app/routes/$network/query/dashboard/rewards.tsx index 56ab128da..febfe17aa 100644 --- a/web/app.fluidity.money/app/routes/$network/query/dashboard/rewards.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/dashboard/rewards.tsx @@ -131,6 +131,7 @@ export const loader: LoaderFunction = async ({ request, params }) => { loaded: true, } satisfies RewardsLoaderData); } catch (err) { + console.log("fetching rewards:", err); throw new Error(`Could not fetch Rewards on ${network}: ${err}`); } // Fail silently - for now. }; From 430edf169462fd74bfdb97c49ba0b6ee515ccd68 Mon Sep 17 00:00:00 2001 From: user Date: Mon, 8 Jan 2024 20:15:19 +1030 Subject: [PATCH 09/18] Reenable referral modal from the dashboard --- .../app/queries/useUserActionsAggregate.ts | 8 +-- .../app/routes/$network/dashboard.tsx | 60 +++++++++---------- .../$network/dashboard/airdrop/index.tsx | 2 - 3 files changed, 33 insertions(+), 37 deletions(-) diff --git a/web/app.fluidity.money/app/queries/useUserActionsAggregate.ts b/web/app.fluidity.money/app/queries/useUserActionsAggregate.ts index c3dd351de..b574c4f43 100644 --- a/web/app.fluidity.money/app/queries/useUserActionsAggregate.ts +++ b/web/app.fluidity.money/app/queries/useUserActionsAggregate.ts @@ -17,7 +17,7 @@ export type AggregatedTransaction = Omit< const queryByAddress: Queryable = { arbitrum: gql` query AggregatedUserTransactionsByAddress($offset: Int = 0, $limit: Int = 12, $address: String!, $token: String) { - arbitrum: aggregated_user_transactions_lootboxes( + arbitrum: aggregated_user_transactions_lootbottles( order_by: {time: desc}, limit: $limit, offset: $offset, @@ -53,7 +53,7 @@ const queryByAddress: Queryable = { `, solana: gql` query AggregatedUserTransactionsByAddress($offset: Int = 0, $limit: Int = 12, $address: String!) { - solana: aggregated_user_transactions_lootboxes( + solana: aggregated_user_transactions_lootbottles( order_by: {time: desc}, limit: $limit, offset: $offset, @@ -91,7 +91,7 @@ const queryByAddress: Queryable = { const queryAll: Queryable = { arbitrum: gql` query aggregatedUserTransactionsAll ($offset: Int = 0, $limit: Int = 12) { - arbitrum: aggregated_user_transactions_lootboxes(order_by: {time: desc}, limit: $limit, offset: $offset, where: {network: {_eq: "arbitrum"}, type: {_is_null: false}}) { + arbitrum: aggregated_user_transactions_lootbottles(order_by: {time: desc}, limit: $limit, offset: $offset, where: {network: {_eq: "arbitrum"}, type: {_is_null: false}}) { value: amount application network @@ -114,7 +114,7 @@ const queryAll: Queryable = { `, solana: gql` query aggregatedUserTransactionsAll ($offset: Int = 0, $limit: Int = 12) { - solana: aggregated_user_transactions_lootboxes(order_by: {time: desc}, limit: $limit, offset: $offset, where: {network: {_eq: "solana"}, type: {_is_null: false}}) { + solana: aggregated_user_transactions_lootbottles(order_by: {time: desc}, limit: $limit, offset: $offset, where: {network: {_eq: "solana"}, type: {_is_null: false}}) { value: amount application network diff --git a/web/app.fluidity.money/app/routes/$network/dashboard.tsx b/web/app.fluidity.money/app/routes/$network/dashboard.tsx index fdf562c2b..eb585bbc9 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard.tsx @@ -461,38 +461,36 @@ export default function Dashboard() { {/* Referral Modal */} - {false && ( - setReferralModalVisibility(false)} - cardPositionStyle={{ - position: "absolute", - top: "1em", - right: isTablet ? "20px" : "60px", - width: 500, + setReferralModalVisibility(false)} + cardPositionStyle={{ + position: "absolute", + top: "1em", + right: isTablet ? "20px" : "60px", + width: 500, + }} + color="holo" + style={{ padding: 0, width: "100%" }} + > + { + setReferralModalVisibility(false); + setWalletModalVisibility(true); }} - color="holo" - style={{ padding: 0, width: "100%" }} - > - { - setReferralModalVisibility(false); - setWalletModalVisibility(true); - }} - referrerClaimed={numActiveReferrerReferrals} - refereeClaimed={numActiveReferreeReferrals} - refereeUnclaimed={numInactiveReferreeReferrals} - progress={inactiveReferrals[0]?.progress || 0} - progressReq={10} - referralCode={referralCode} - loaded={referralCountLoaded} - closeModal={() => setReferralModalVisibility(false)} - /> - - )} + referrerClaimed={numActiveReferrerReferrals} + refereeClaimed={numActiveReferreeReferrals} + refereeUnclaimed={numInactiveReferreeReferrals} + progress={inactiveReferrals[0]?.progress || 0} + progressReq={10} + referralCode={referralCode} + loaded={referralCountLoaded} + closeModal={() => setReferralModalVisibility(false)} + /> + {/* Accept Referral Modal */} { address ? `/${network}/query/dashboard/airdrop?address=${address}&epoch=${EPOCH_CURRENT_IDENTIFIER}` : "" ); - console.log("airdropData", airdropData); - const { data: airdropLeaderboardData } = useCache( `/${network}/query/dashboard/airdropLeaderboard?period=${ leaderboardFilterIndex === 0 ? "24" : "all" From 2be289a1e13fa872fd78bab2305efc79f3e99e70 Mon Sep 17 00:00:00 2001 From: user Date: Tue, 9 Jan 2024 14:07:04 +1030 Subject: [PATCH 10/18] Fix mistake in surfing provider --- web/surfing/src/types/provider.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/surfing/src/types/provider.ts b/web/surfing/src/types/provider.ts index bd87b73c5..ad579fe80 100644 --- a/web/surfing/src/types/provider.ts +++ b/web/surfing/src/types/provider.ts @@ -31,5 +31,5 @@ export type Provider = | "Uniswap" | "XY Finance" | "Ramses" - | "Jumper"; + | "Jumper" | "Meteora"; From bc1d8debdd94e98cd2b1b28d6bbb2b54f337c47a Mon Sep 17 00:00:00 2001 From: user Date: Tue, 9 Jan 2024 16:30:01 +1030 Subject: [PATCH 11/18] Rename recipient to winner in the use of the lootbox winners aggregate table --- .../20231219094456-lootbox_config_add_prev_epoch.sql | 2 +- .../20231228172908-lootbox_amounts_earned_create.sql | 8 ++++---- ...rdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql | 8 ++++---- ...103945-airdrop_leaderboard_add_epoch_and_arb_fusdc.sql | 8 ++++---- .../20240105003308-airdrop_leaderboard_add_epoch.sql | 8 ++++---- lib/databases/timescale/lootboxes/rewards.go | 2 +- 6 files changed, 18 insertions(+), 18 deletions(-) diff --git a/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql b/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql index a1587e2de..9adc04dbd 100644 --- a/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql +++ b/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql @@ -18,7 +18,7 @@ CREATE TABLE lootbox_config ( -- the enum epoch_identifier lootbox_epoch NOT NULL UNIQUE, - -- ethereum_application that should the current focus of the lootbox + -- ethereum_application that should be the current focus of the lootbox -- mini leaderboard competitions (and should be displayed in the UI -- with the right query) ethereum_application ethereum_application NOT NULL DEFAULT 'none' diff --git a/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql b/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql index dec7a2b8b..c79a76769 100644 --- a/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql +++ b/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql @@ -4,7 +4,7 @@ -- itself over time on a per-epoch basis. it does so so we can track -- cleanly in the UI the amounts earned for the lootbox presentation --- the recipient field is converted from the solana winner owner +-- the winner field is converted from the solana winner owner -- address implicitly in the go code currently! -- we're okay with DECIMAL as we can store the floating amount with a @@ -19,14 +19,14 @@ CREATE TABLE lootbox_amounts_rewarded ( -- decimals. can be lossy amount_earned DECIMAL NOT NULL, - -- recipient of the winning amount (the winner) - recipient VARCHAR NOT NULL, + -- winner of the winning (the recipient of the winning payout) + winner VARCHAR NOT NULL, application VARCHAR NOT NULL, last_updated TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -- id to prevent duplication during the upsert for updating amounts - CONSTRAINT id PRIMARY KEY(network, epoch, token_short_name, recipient, application) + CONSTRAINT id PRIMARY KEY(network, epoch, token_short_name, winner, application) ); -- migrate:down diff --git a/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql b/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql index 77387d0ae..d97346668 100644 --- a/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql +++ b/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql @@ -32,15 +32,15 @@ FROM ( GROUP BY address ) lb LEFT JOIN ( - SELECT amount_earned, recipient + SELECT amount_earned, winner FROM lootbox_amounts_rewarded WHERE token_short_name = 'USDC' - ) AS lootbox_amounts_rewarded_fusdc ON lb.address = lootbox_amounts_rewarded_fusdc.recipient + ) AS lootbox_amounts_rewarded_fusdc ON lb.address = lootbox_amounts_rewarded_fusdc.winner LEFT JOIN ( - SELECT amount_earned, recipient + SELECT amount_earned, winner FROM lootbox_amounts_rewarded WHERE token_short_name = 'ARB' - ) AS lootbox_amounts_rewarded_arb ON lb.address = lootbox_amounts_rewarded_arb.recipient + ) AS lootbox_amounts_rewarded_arb ON lb.address = lootbox_amounts_rewarded_arb.winner LEFT JOIN lootbox_referrals ON lb.address = lootbox_referrals.referrer, LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity diff --git a/database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_and_arb_fusdc.sql b/database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_and_arb_fusdc.sql index d145a40c3..0da4d791a 100644 --- a/database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_and_arb_fusdc.sql +++ b/database/102-up-timescale/20240103103945-airdrop_leaderboard_add_epoch_and_arb_fusdc.sql @@ -27,15 +27,15 @@ FROM ( GROUP BY address ) lb_24_application LEFT JOIN ( - SELECT amount_earned, recipient + SELECT amount_earned, winner FROM lootbox_amounts_rewarded WHERE token_short_name = 'USDC' - ) AS lootbox_amounts_rewarded_fusdc ON lb_24_application.address = lootbox_amounts_rewarded_fusdc.recipient + ) AS lootbox_amounts_rewarded_fusdc ON lb_24_application.address = lootbox_amounts_rewarded_fusdc.winner LEFT JOIN ( - SELECT amount_earned, recipient + SELECT amount_earned, winner FROM lootbox_amounts_rewarded WHERE token_short_name = 'ARB' - ) AS lootbox_amounts_rewarded_arb ON lb_24_application.address = lootbox_amounts_rewarded_arb.recipient + ) AS lootbox_amounts_rewarded_arb ON lb_24_application.address = lootbox_amounts_rewarded_arb.winner LEFT JOIN lootbox_referrals ON lb_24_application.address = lootbox_referrals.referrer, LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity diff --git a/database/102-up-timescale/20240105003308-airdrop_leaderboard_add_epoch.sql b/database/102-up-timescale/20240105003308-airdrop_leaderboard_add_epoch.sql index 96a10036f..2b1e21463 100644 --- a/database/102-up-timescale/20240105003308-airdrop_leaderboard_add_epoch.sql +++ b/database/102-up-timescale/20240105003308-airdrop_leaderboard_add_epoch.sql @@ -26,15 +26,15 @@ FROM ( GROUP BY address ) lb LEFT JOIN ( - SELECT amount_earned, recipient + SELECT amount_earned, winner FROM lootbox_amounts_rewarded WHERE token_short_name = 'USDC' - ) AS lootbox_amounts_rewarded_fusdc ON lb.address = lootbox_amounts_rewarded_fusdc.recipient + ) AS lootbox_amounts_rewarded_fusdc ON lb.address = lootbox_amounts_rewarded_fusdc.winner LEFT JOIN ( - SELECT amount_earned, recipient + SELECT amount_earned, winner FROM lootbox_amounts_rewarded WHERE token_short_name = 'ARB' - ) AS lootbox_amounts_rewarded_arb ON lb.address = lootbox_amounts_rewarded_arb.recipient + ) AS lootbox_amounts_rewarded_arb ON lb.address = lootbox_amounts_rewarded_arb.winner LEFT JOIN lootbox_referrals ON lb.address = lootbox_referrals.referrer, LATERAL calculate_a_y(address, now()::TIMESTAMP) AS liquidity diff --git a/lib/databases/timescale/lootboxes/rewards.go b/lib/databases/timescale/lootboxes/rewards.go index 7d9aa1a25..27cd74345 100644 --- a/lib/databases/timescale/lootboxes/rewards.go +++ b/lib/databases/timescale/lootboxes/rewards.go @@ -290,7 +290,7 @@ func UpdateOrInsertAmountsRewarded(network_ network.BlockchainNetwork, lootboxCu epoch, token_short_name, amount_earned, - recipient, + winner, application, last_updated ) From 0ee45d2a36defddec284faa387ce4128c3732bfa Mon Sep 17 00:00:00 2001 From: user Date: Wed, 10 Jan 2024 12:01:54 +1030 Subject: [PATCH 12/18] Update to reflect changes --- automation/fluidity/website/mainnet.yml | 1 + .../main.go | 8 +++++++- .../+Errors | 4 ---- .../main.go | 19 ++++++++++--------- ...19094456-lootbox_config_add_prev_epoch.sql | 4 ++-- ...28172908-lootbox_amounts_earned_create.sql | 2 +- ...board_24_hours_add_epoch_and_arb_fusdc.sql | 4 ++-- web/app.fluidity.money/README.md | 5 +++++ .../$network/query/dashboard/airdrop.tsx | 2 -- .../$network/query/dashboard/rewards.tsx | 1 - .../routes/$network/query/referralBottles.tsx | 2 -- .../app/util/api/graphql.ts | 2 +- web/fluidity.money/Dockerfile.frontend | 2 ++ 13 files changed, 31 insertions(+), 25 deletions(-) delete mode 100644 cmd/microservice-ethereum-create-transaction-lootboxes/+Errors diff --git a/automation/fluidity/website/mainnet.yml b/automation/fluidity/website/mainnet.yml index f5be2dd74..c4ae27dce 100644 --- a/automation/fluidity/website/mainnet.yml +++ b/automation/fluidity/website/mainnet.yml @@ -18,6 +18,7 @@ SERVICES: NEXT_PUBLIC_FLU_SPLIT_BROWSER_KEY: s7ovhvrpv77htn8aqlf2irirnll9ofvr07be NEXT_PUBLIC_FLU_GTAG_ID: G-EF68MNJRJ7 NEXT_PUBLIC_FLU_GTM_ID: GTM-W7QJGR2 + NEXT_PUBLIC_FLU_HASURA_URL: https://fluidity.hasura.app/v1/graphql DOCKER_ARGS: SECRET_FLU_SENTRY_DSN: /fluidity/frontend/sentryURL diff --git a/cmd/connector-common-winners-timescale/main.go b/cmd/connector-common-winners-timescale/main.go index 5f35ef4b3..cce0f97e1 100644 --- a/cmd/connector-common-winners-timescale/main.go +++ b/cmd/connector-common-winners-timescale/main.go @@ -8,14 +8,17 @@ import ( "math" "math/big" - "github.com/fluidity-money/fluidity-app/lib/log" "github.com/fluidity-money/fluidity-app/lib/databases/postgres/solana" "github.com/fluidity-money/fluidity-app/lib/databases/timescale/lootboxes" database "github.com/fluidity-money/fluidity-app/lib/databases/timescale/winners" + "github.com/fluidity-money/fluidity-app/lib/log" queue "github.com/fluidity-money/fluidity-app/lib/queues/winners" "github.com/fluidity-money/fluidity-app/lib/types/network" ) +// lootboxUpdateTrackedRewardAmounts by destructuring the winner, and +// upserting it into the database. queries the current epoch to get what +// should be used. func lootboxUpdateTrackedRewardAmounts(winner queue.Winner) { var ( network_ = winner.Network @@ -51,6 +54,9 @@ func lootboxUpdateTrackedRewardAmounts(winner queue.Winner) { winnerAddress = winner.WinnerAddress } + // we can normalise this and store it in the database to avoid an + // extra check, as we can afford some loss in this calculation. + decimals := math.Pow10(tokenDecimals) amountNormal := new(big.Rat).SetInt(amountWon) diff --git a/cmd/microservice-ethereum-create-transaction-lootboxes/+Errors b/cmd/microservice-ethereum-create-transaction-lootboxes/+Errors deleted file mode 100644 index 794938511..000000000 --- a/cmd/microservice-ethereum-create-transaction-lootboxes/+Errors +++ /dev/null @@ -1,4 +0,0 @@ -//: Permission denied -: exit 1 -//: Permission denied -//: Permission denied diff --git a/cmd/microservice-lootbox-reward-top-winners/main.go b/cmd/microservice-lootbox-reward-top-winners/main.go index d5516f77b..eabe0fa9d 100644 --- a/cmd/microservice-lootbox-reward-top-winners/main.go +++ b/cmd/microservice-lootbox-reward-top-winners/main.go @@ -57,19 +57,20 @@ func main() { // if there's a current application focus, then we want to reward only specific winners - if currentApplication != application.ApplicationNone { - // fetch and log the top 10 users for a specific application - topUsers = lootboxes.GetTopApplicationUsersByLootboxCount( + switch currentApplication { + case applications.ApplicationNone: + topUsers = lootboxes.GetTopUsersByLootboxCount( + currentEpoch, startTime, endTime, - currentApplication, - currentEpoch, ) - } else { - topUsers = lootboxes.GetTopUsersByLootboxCount( + default: + // fetch and log the top 10 users for a specific application + topUsers = lootboxes.GetTopApplicationUsersByLootboxCount( + currentEpoch, startTime, endTime, - currentEpoch, + currentApplication, ) } @@ -86,5 +87,5 @@ func main() { } // reward the top 10 users - lootboxes.InsertTopUserReward(startTime, topUsers) + lootboxes.InsertTopUserReward(currentEpoch, startTime, topUsers) } diff --git a/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql b/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql index 9adc04dbd..fa75fd5a6 100644 --- a/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql +++ b/database/102-up-timescale/20231219094456-lootbox_config_add_prev_epoch.sql @@ -8,11 +8,11 @@ CREATE TABLE lootbox_config ( -- program_begin_date to begin counting lootbottles from -- this date onwards, in UTC - program_begin TIMESTAMP, + program_begin TIMESTAMP WITHOUT TIME ZONE NOT NULL, -- program_end to use as the final date for the epoch, and -- when to stop counting (also in UTC) - program_end TIMESTAMP, + program_end TIMESTAMP WITHOUT TIME ZONE NOT NULL, -- epoch_identifier to use as the identifier for the epoch with -- the enum diff --git a/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql b/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql index c79a76769..839cf1e2a 100644 --- a/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql +++ b/database/102-up-timescale/20231228172908-lootbox_amounts_earned_create.sql @@ -17,7 +17,7 @@ CREATE TABLE lootbox_amounts_rewarded ( -- the amount earned, normalised according to the underlying -- decimals. can be lossy - amount_earned DECIMAL NOT NULL, + amount_earned NUMERIC NOT NULL, -- winner of the winning (the recipient of the winning payout) winner VARCHAR NOT NULL, diff --git a/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql b/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql index d97346668..6f8286e07 100644 --- a/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql +++ b/database/102-up-timescale/20240102213501-airdrop_leaderboard_24_hours_add_epoch_and_arb_fusdc.sql @@ -5,8 +5,8 @@ DROP FUNCTION airdrop_leaderboard_24_hours; ALTER TABLE airdrop_leaderboard_return - ADD COLUMN fusdc_earned DECIMAL NOT NULL, - ADD COLUMN arb_earned DECIMAL NOT NULL; + ADD COLUMN fusdc_earned NUMERIC NOT NULL, + ADD COLUMN arb_earned NUMERIC NOT NULL; CREATE FUNCTION airdrop_leaderboard_24_hours(epoch_ lootbox_epoch) RETURNS SETOF airdrop_leaderboard_return diff --git a/web/app.fluidity.money/README.md b/web/app.fluidity.money/README.md index 38174ccec..824204cf5 100644 --- a/web/app.fluidity.money/README.md +++ b/web/app.fluidity.money/README.md @@ -17,6 +17,11 @@ | `FLU_SENTRY_DSN` | Sentry reporting URI | | `FLU_SPLIT_BROWSER_KEY` | Split Client-Side Key | | `FLU_WALLETCONNECT_ID` | WalletConnect Client-Side Project ID | +| `FLU_HASURA_URL` | Hasura API URL | + +### Note on the Hasura API URL + +This is also set manually in `app/util/api/graphql.ts`. ## Building diff --git a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx index 960da8fbe..a9cc70f12 100644 --- a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx @@ -65,7 +65,6 @@ export const loader: LoaderFunction = async ({ params, request }) => { }); if (errors) { - console.log("errors", errors); captureException(errors, { tags: { section: "airdrop", @@ -161,7 +160,6 @@ export const loader: LoaderFunction = async ({ params, request }) => { section: "network/index", }, }); - console.log("ccccc", err); return new Error("Server could not fulfill request"); } }; diff --git a/web/app.fluidity.money/app/routes/$network/query/dashboard/rewards.tsx b/web/app.fluidity.money/app/routes/$network/query/dashboard/rewards.tsx index febfe17aa..56ab128da 100644 --- a/web/app.fluidity.money/app/routes/$network/query/dashboard/rewards.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/dashboard/rewards.tsx @@ -131,7 +131,6 @@ export const loader: LoaderFunction = async ({ request, params }) => { loaded: true, } satisfies RewardsLoaderData); } catch (err) { - console.log("fetching rewards:", err); throw new Error(`Could not fetch Rewards on ${network}: ${err}`); } // Fail silently - for now. }; diff --git a/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx b/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx index 2b11f29f4..820ec2029 100644 --- a/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx @@ -25,8 +25,6 @@ export const loader: LoaderFunction = async ({ request }) => { const { data: referralBottleCountData, errors: referralBottleCountErr } = await useReferralLootboxesByAddress(epoch, address); - console.log("errors", referralBottleCountErr); - if (referralBottleCountErr || !referralBottleCountData) { throw new Error("Could not fetch Referral Bottles"); } diff --git a/web/app.fluidity.money/app/util/api/graphql.ts b/web/app.fluidity.money/app/util/api/graphql.ts index 3636e33b8..d112f9b87 100644 --- a/web/app.fluidity.money/app/util/api/graphql.ts +++ b/web/app.fluidity.money/app/util/api/graphql.ts @@ -11,7 +11,7 @@ type GqlEndpoint = { type GqlBackend = "hasura"; -const HasuraUrl = "http://localhost:8080/v1/graphql"; +const HasuraUrl = "https://fluidity.hasura.app/v1/graphql"; export const networkGqlBackend = (network: string): GqlBackend | null => { switch (network) { diff --git a/web/fluidity.money/Dockerfile.frontend b/web/fluidity.money/Dockerfile.frontend index 1706b1d9d..161cb8c98 100644 --- a/web/fluidity.money/Dockerfile.frontend +++ b/web/fluidity.money/Dockerfile.frontend @@ -11,6 +11,8 @@ ARG GITHUB_TOKEN ARG NEXT_PUBLIC_FLU_ETH_RPC_HTTP +ARG NEXT_PUBLIC_FLU_HASURA_URL + ENV CI $CI ENV PATH /app/node_modules.bin:$PATH From ce56be2c4e48541676057ef7144b08e2109b29da Mon Sep 17 00:00:00 2001 From: user Date: Wed, 10 Jan 2024 13:58:26 +1030 Subject: [PATCH 13/18] Some changes to support redirecting on just the network name, and some testing requirements --- .../main.go | 4 +- .../main.go | 6 ++- common/ethereum/applications/applications.go | 3 +- .../timescale/lootboxes/lootboxes.go | 4 +- tests/pipeline/transaction_lootbox_test.go | 2 +- .../JoeFarmlandsOrCamelotKingdom/index.tsx | 5 +- .../app/queries/addReferral.ts | 6 ++- .../app/queries/useLootboxConfig.ts | 1 - .../app/queries/useReferralCode.ts | 12 ++++- .../app/queries/useUserUnclaimedRewards.ts | 6 ++- .../$network/dashboard/airdrop/index.tsx | 53 +------------------ .../app/routes/$network/dashboard/home.tsx | 1 + .../$network/query/dashboard/airdrop.tsx | 5 +- .../app/routes/arbitrum/index.tsx | 5 ++ .../app/routes/polygon_zk/index.tsx | 5 ++ .../app/routes/solana/index.tsx | 5 ++ 16 files changed, 51 insertions(+), 72 deletions(-) create mode 100644 web/app.fluidity.money/app/routes/arbitrum/index.tsx create mode 100644 web/app.fluidity.money/app/routes/polygon_zk/index.tsx create mode 100644 web/app.fluidity.money/app/routes/solana/index.tsx diff --git a/cmd/connector-common-lootboxes-timescale/main.go b/cmd/connector-common-lootboxes-timescale/main.go index ab05975c4..b7f0d2e10 100644 --- a/cmd/connector-common-lootboxes-timescale/main.go +++ b/cmd/connector-common-lootboxes-timescale/main.go @@ -6,7 +6,5 @@ import ( ) func main() { - queue.LootboxesAll(func(lootbox lootboxes.Lootbox) { - lootboxes.InsertLootbox(lootbox) - }) + queue.LootboxesAll(lootboxes.InsertLootbox) } diff --git a/cmd/microservice-redeem-testnet-lootboxes/main.go b/cmd/microservice-redeem-testnet-lootboxes/main.go index 0c059b335..90ed02578 100644 --- a/cmd/microservice-redeem-testnet-lootboxes/main.go +++ b/cmd/microservice-redeem-testnet-lootboxes/main.go @@ -119,6 +119,7 @@ func main() { AwardedTime: currentTime, LootboxCount: LootboxCountCommon, RewardTier: 1, + Epoch: currentEpoch, }, { Address: testnetOwnerString, @@ -126,6 +127,7 @@ func main() { AwardedTime: currentTime, LootboxCount: LootboxCountUncommon, RewardTier: 2, + Epoch: currentEpoch, }, { Address: testnetOwnerString, @@ -133,6 +135,7 @@ func main() { AwardedTime: currentTime, LootboxCount: LootboxCountRare, RewardTier: 3, + Epoch: currentEpoch, }, { Address: testnetOwnerString, @@ -140,11 +143,12 @@ func main() { AwardedTime: currentTime, LootboxCount: LootboxCountUltraRare, RewardTier: 4, + Epoch: currentEpoch, }, } for _, lootbox := range boxes { - lootboxes.InsertLootbox(lootbox, currentEpoch) + lootboxes.InsertLootbox(lootbox) } }) } diff --git a/common/ethereum/applications/applications.go b/common/ethereum/applications/applications.go index 9e4349fdc..eaf96096e 100644 --- a/common/ethereum/applications/applications.go +++ b/common/ethereum/applications/applications.go @@ -66,6 +66,8 @@ const ( ApplicationWombat ApplicationSeawaterAmm ApplicationTraderJoe + ApplicationRamses + ApplicationJumper ) // ParseApplicationName shadows the lib types definition @@ -390,7 +392,6 @@ func GetApplicationTransferParties(transaction ethereum.Transaction, transfer wo // Gave the majority payout to the swap-maker (i.e. transaction sender) // and rest to pool return transaction.From, logAddress, nil - default: return nilAddress, nilAddress, fmt.Errorf( "Transfer #%v did not contain an application", diff --git a/lib/databases/timescale/lootboxes/lootboxes.go b/lib/databases/timescale/lootboxes/lootboxes.go index 031fc07b3..55e46c516 100644 --- a/lib/databases/timescale/lootboxes/lootboxes.go +++ b/lib/databases/timescale/lootboxes/lootboxes.go @@ -34,7 +34,7 @@ const ( type Lootbox = types.Lootbox // InsertLootbox inserts a Lootbox into the database -func InsertLootbox(lootbox Lootbox, currentEpoch string) { +func InsertLootbox(lootbox Lootbox) { timescaleClient := timescale.Client() statementText := fmt.Sprintf( @@ -88,7 +88,7 @@ func InsertLootbox(lootbox Lootbox, currentEpoch string) { } // GetLootboxes gets all Lootboxes earned by address, limited by a number -func GetLootboxes(address ethereum.Address, currentEpoch string, limit int) []Lootbox { +func GetLootboxes(currentEpoch string, address ethereum.Address, limit int) []Lootbox { timescaleClient := timescale.Client() statementText := fmt.Sprintf( diff --git a/tests/pipeline/transaction_lootbox_test.go b/tests/pipeline/transaction_lootbox_test.go index 16a42f7cc..fc854cedd 100644 --- a/tests/pipeline/transaction_lootbox_test.go +++ b/tests/pipeline/transaction_lootbox_test.go @@ -116,7 +116,7 @@ func TestTransactionLootboxes(t *testing.T) { time.Sleep(time.Second) - allLootboxes := lootboxes_db.GetLootboxes(senderAddress, 1) + allLootboxes := lootboxes_db.GetLootboxes("epoch_1", senderAddress, 1) assert.Len(t, allLootboxes, 1) expectedLootbox := lootboxes.Lootbox{ diff --git a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx index 5be892e19..3d11b0517 100644 --- a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx +++ b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx @@ -3,10 +3,7 @@ import styles from "./styles.css"; export const JoeFarmlandsOrCamelotKingdomLinks = () => [{ rel: "stylesheet", href: styles }]; -interface IJoeFarmlandsOrCamelotKingdomProps { -}; - -const JoeFarmlandsOrCamelotKingdom = (props: IJoeFarmlandsOrCamelotKingdomProps) => { +const JoeFarmlandsOrCamelotKingdom = () => { return (
diff --git a/web/app.fluidity.money/app/queries/addReferral.ts b/web/app.fluidity.money/app/queries/addReferral.ts index 275640ec2..18ad5b588 100644 --- a/web/app.fluidity.money/app/queries/addReferral.ts +++ b/web/app.fluidity.money/app/queries/addReferral.ts @@ -40,8 +40,12 @@ const addReferral = (referrer: string, referee: string) => { variables, }; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + return jsonPost( - process.env.FLU_HASURA_URL!, + url, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useLootboxConfig.ts b/web/app.fluidity.money/app/queries/useLootboxConfig.ts index 1b619055c..3fe61a3fc 100644 --- a/web/app.fluidity.money/app/queries/useLootboxConfig.ts +++ b/web/app.fluidity.money/app/queries/useLootboxConfig.ts @@ -1,4 +1,3 @@ -import { BottleTiers } from "~/routes/$network/query/dashboard/airdrop"; import { jsonPost, gql, fetchInternalEndpoint } from "~/util"; const queryGetConfigCurrentProgram = gql` diff --git a/web/app.fluidity.money/app/queries/useReferralCode.ts b/web/app.fluidity.money/app/queries/useReferralCode.ts index 1b5019591..4098e0bd5 100644 --- a/web/app.fluidity.money/app/queries/useReferralCode.ts +++ b/web/app.fluidity.money/app/queries/useReferralCode.ts @@ -54,8 +54,12 @@ const useReferralCodeByAddress = (address: string) => { variables, }; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + return jsonPost( - process.env.FLU_HASURA_URL!, + url, body, process.env.FLU_HASURA_SECRET ? { @@ -75,8 +79,12 @@ const useReferralCodeByCode = (code: string) => { variables, }; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + return jsonPost( - process.env.FLU_HASURA_URL!, + url, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts b/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts index a50ddd937..6bb606572 100644 --- a/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts +++ b/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts @@ -82,10 +82,12 @@ const useUserUnclaimedRewards = async (network: string, address: string) => { }, }; - const fluGqlEndpoint = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); return jsonPost( - fluGqlEndpoint, + url, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx index e987bdc30..d3fd7cf86 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx @@ -24,7 +24,6 @@ import { BloomEffect, toSignificantDecimals, useViewport, - numberToMonetaryString, } from "@fluidity-money/surfing"; import { BottlesDetailsModal, @@ -34,7 +33,6 @@ import { StakingStatsModal, TutorialModal, RecapModal, - stakingLiquidityMultiplierEq, TestnetRewardsModal, } from "./common"; import { motion } from "framer-motion"; @@ -58,7 +56,6 @@ import Table, { IRow } from "~/components/Table"; import { ReferralBottlesCountLoaderData } from "../../query/referralBottles"; import { HowItWorksContent } from "~/components/ReferralModal"; import JoeFarmlandsOrCamelotKingdom from "~/components/JoeFarmlandsOrCamelotKingdom"; -import { LootboxConfig } from "~/queries/useLootboxConfig"; const EPOCH_CURRENT_IDENTIFIER = "epoch_1"; @@ -202,7 +199,6 @@ const Airdrop = () => { address, balance, stakeTokens, - getStakingDeposits, testStakeTokens, getStakingRatios, redeemableTokens: getRedeemableTokens, @@ -264,13 +260,8 @@ const Airdrop = () => { bottlesCount, wethPrice, usdcPrice, - programBegin, - programEnd, epochDaysTotal, epochDaysElapsed, - epochIdentifier, - ethereumApplication, - epochFound, }, referrals: { numActiveReferreeReferrals, @@ -302,7 +293,7 @@ const Airdrop = () => { setCurrentModal(isAirdropModal(destModal) ? destModal : null); }, [location.hash]); - const [stakes, setStakes] = useState< + const [stakes, _] = useState< Array<{ fluidAmount: BN; baseAmount: BN; @@ -570,7 +561,7 @@ const Airdrop = () => { size="small" groupId="airdrop" > - + Dune @@ -1284,46 +1275,6 @@ const MyMultiplier = ({ usdcPrice, isMobile = false, }: IMyMultiplier) => { - const sumLiquidityMultiplier = stakes.reduce( - (sum, { fluidAmount, baseAmount, durationDays, depositDate }) => { - const fluidDecimals = 6; - const fluidUsd = getUsdFromTokenAmount( - fluidAmount, - fluidDecimals, - usdcPrice - ); - - const wethDecimals = 18; - const usdcDecimals = 6; - - // If converting base amount by weth decimals (18) is smaller than $0.01, - // then tentatively assume Token amount is USDC - // A false hit would be a USDC deposit >= $100,000 - const baseUsd = - getUsdFromTokenAmount(baseAmount, wethDecimals, wethPrice) < 0.01 - ? getUsdFromTokenAmount(baseAmount, usdcDecimals, usdcPrice) - : getUsdFromTokenAmount(baseAmount, wethDecimals, wethPrice); - - const stakedDays = dayDifference(new Date(), new Date(depositDate)); - - const multiplier = stakingLiquidityMultiplierEq(stakedDays, durationDays); - - return sum + (fluidUsd + baseUsd) * multiplier; - }, - 0 - ); - - // if there are no stakes, this renders an empty stake on the dashboard which is A PART OF THE DESIGN SPEC - if (stakes.length === 0) - stakes = [ - { - fluidAmount: new BN(0), - baseAmount: new BN(0), - durationDays: 0, - depositDate: new Date(), - }, - ]; - return (
{sender === MintAddress diff --git a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx index a9cc70f12..714546e9c 100644 --- a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx @@ -4,7 +4,6 @@ import { JsonRpcProvider } from "@ethersproject/providers"; import { LoaderFunction, json } from "@remix-run/node"; import { captureException } from "@sentry/react"; import { useAirdropStatsByAddress } from "~/queries/useAirdropStats"; -import { useStakingDataByAddress } from "~/queries/useStakingData"; import { useLootboxConfig } from "~/queries"; import { getWethUsdPrice } from "~/util/chainUtils/ethereum/transaction"; import EACAggregatorProxyAbi from "~/util/chainUtils/ethereum/EACAggregatorProxy.json"; @@ -53,14 +52,14 @@ export const loader: LoaderFunction = async ({ params, request }) => { const url = new URL(request.url); const address_ = url.searchParams.get("address"); - const epochIdentifier = url.searchParams.get("epoch"); + const epochIdentifier = url.searchParams.get("epoch") ?? ""; const address = address_?.toLowerCase(); if (!address || !network || !epochIdentifier) throw new Error("Invalid Request"); const { data, errors } = await useLootboxConfig({ - identifier: epochIdentifier!, + identifier: epochIdentifier, shouldFind: false }); diff --git a/web/app.fluidity.money/app/routes/arbitrum/index.tsx b/web/app.fluidity.money/app/routes/arbitrum/index.tsx new file mode 100644 index 000000000..36f70df78 --- /dev/null +++ b/web/app.fluidity.money/app/routes/arbitrum/index.tsx @@ -0,0 +1,5 @@ +import { LoaderFunction, redirect } from "@remix-run/node"; + +export const loader: LoaderFunction = async () => { + return redirect(`/arbitrum/dashboard/home`); +}; diff --git a/web/app.fluidity.money/app/routes/polygon_zk/index.tsx b/web/app.fluidity.money/app/routes/polygon_zk/index.tsx new file mode 100644 index 000000000..b83703f40 --- /dev/null +++ b/web/app.fluidity.money/app/routes/polygon_zk/index.tsx @@ -0,0 +1,5 @@ +import { LoaderFunction, redirect } from "@remix-run/node"; + +export const loader: LoaderFunction = async () => { + return redirect(`/polygon_zk/dashboard/home`); +}; diff --git a/web/app.fluidity.money/app/routes/solana/index.tsx b/web/app.fluidity.money/app/routes/solana/index.tsx new file mode 100644 index 000000000..8d02d7a2a --- /dev/null +++ b/web/app.fluidity.money/app/routes/solana/index.tsx @@ -0,0 +1,5 @@ +import { LoaderFunction, redirect } from "@remix-run/node"; + +export const loader: LoaderFunction = async () => { + return redirect(`/solana/dashboard/home`); +}; From 9b4cedf3be690b5250ba4bf8d9801a8207e6a471 Mon Sep 17 00:00:00 2001 From: user Date: Wed, 10 Jan 2024 14:52:44 +1030 Subject: [PATCH 14/18] Fix lootbox insertion test --- lib/databases/timescale/lootboxes/rewards.go | 8 ++++---- lib/databases/timescale/lootboxes/rewards_test.go | 12 ++++++------ 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/databases/timescale/lootboxes/rewards.go b/lib/databases/timescale/lootboxes/rewards.go index 27cd74345..a0df54a3b 100644 --- a/lib/databases/timescale/lootboxes/rewards.go +++ b/lib/databases/timescale/lootboxes/rewards.go @@ -25,7 +25,7 @@ type UserLootboxCount struct { } // buildUserRewardValuesString to build a variadic string for the values to insert for top winners -func buildUserRewardValuesString(currentEpoch string, userCount int) (string, error) { +func buildUserRewardValuesString(userCount int) (string, error) { if userCount < 1 || userCount > 10 { return "", fmt.Errorf( "invalid number of leaderboard users - want 1-10, got %d", @@ -38,11 +38,11 @@ func buildUserRewardValuesString(currentEpoch string, userCount int) (string, er ($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), ($3, '', 'leaderboard_prize', $1, 0, 3, 5, 'none', $2)`, - `($3, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), + `($4, '', 'leaderboard_prize', $1, 0, 1, 20, 'none', $2), ($4, '', 'leaderboard_prize', $1, 0, 2, 5, 'none', $2), ($4, '', 'leaderboard_prize', $1, 0, 3, 2, 'none', $2)`, - `($4, '', 'leaderboard_prize', $1, 0, 1, 15, 'none', $2), + `($5, '', 'leaderboard_prize', $1, 0, 1, 15, 'none', $2), ($5, '', 'leaderboard_prize', $1, 0, 2, 3, 'none', $2), ($5, '', 'leaderboard_prize', $1, 0, 3, 1, 'none', $2)`, @@ -102,7 +102,7 @@ func buildUserRewardValuesString(currentEpoch string, userCount int) (string, er // InsertTopUserReward to insert lootboxes for the given users for their activity during the airdrop. // Expects 10 users to reward func InsertTopUserReward(currentEpoch string, currentTime time.Time, users []UserLootboxCount) { - valuesString, err := buildUserRewardValuesString(currentEpoch, len(users)) + valuesString, err := buildUserRewardValuesString(len(users)) if err != nil { log.Fatal(func(k *log.Log) { diff --git a/lib/databases/timescale/lootboxes/rewards_test.go b/lib/databases/timescale/lootboxes/rewards_test.go index 06e3cfa09..707382fa6 100644 --- a/lib/databases/timescale/lootboxes/rewards_test.go +++ b/lib/databases/timescale/lootboxes/rewards_test.go @@ -115,7 +115,7 @@ func TestBuildUserRewardValuesString(t *testing.T) { ($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), ($9, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), ($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), -($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)`, +($11, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)`, `($3, '', 'leaderboard_prize', $1, 0, 1, 30, 'none', $2), ($3, '', 'leaderboard_prize', $1, 0, 2, 10, 'none', $2), @@ -132,23 +132,23 @@ func TestBuildUserRewardValuesString(t *testing.T) { ($8, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), ($9, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), ($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), -($10, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), -($11, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)`, +($11, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2), +($12, '', 'leaderboard_prize', $1, 0, 1, 10, 'none', $2)`, } for i, expectedString := range expectedRewardStrings { userCount := i + 1 - rewardString, err := buildUserRewardValuesString("epoch_1", userCount) + rewardString, err := buildUserRewardValuesString(userCount) require.NoError(t, err) assert.Equal(t, expectedString, rewardString) } - rewardString, err := buildUserRewardValuesString("epoch_1", 0) + rewardString, err := buildUserRewardValuesString(0) assert.Empty(t, rewardString) assert.Error(t, err) - rewardString, err = buildUserRewardValuesString("epoch_1", 11) + rewardString, err = buildUserRewardValuesString(11) assert.Empty(t, rewardString) assert.Error(t, err) } From d18108325c194fd6a2473e25dff5b7ae0482be2d Mon Sep 17 00:00:00 2001 From: user Date: Wed, 10 Jan 2024 15:16:31 +1030 Subject: [PATCH 15/18] Fix linting errors related to using the env for hasura --- common/ethereum/applications/jumper/init.go | 22 +- common/ethereum/applications/jumper/jumper.go | 15 -- .../JoeFarmlandsOrCamelotKingdom/index.tsx | 13 +- .../JoeFarmlandsOrCamelotKingdom/styles.css | 3 +- .../app/queries/addReferralCode.ts | 6 +- .../app/queries/useAirdropLeaderboard.ts | 29 ++- .../app/queries/useAirdropStats.ts | 5 +- .../queries/useApplicationRewardStatistics.ts | 6 +- .../app/queries/useAssetStatistics.ts | 6 +- .../app/queries/useGlobalRewardStatistics.ts | 4 +- .../app/queries/useHighestRewardStatistics.ts | 8 +- .../app/queries/useLootBottles.ts | 6 +- .../app/queries/useLootboxConfig.ts | 42 ++-- .../app/queries/useReferralCount.ts | 18 +- .../app/queries/useReferrals.ts | 12 +- .../app/queries/useStakingData.ts | 6 +- .../app/queries/useTokenRewardStatistics.ts | 4 +- .../app/queries/useTokens.ts | 6 +- .../app/queries/useUserActionsAggregate.ts | 225 ++++++++++-------- .../app/queries/useUserRewards.ts | 18 +- .../app/queries/useUserTransactions.ts | 2 +- .../app/queries/useUserYield.ts | 8 +- .../app/queries/useVolumeStats.ts | 8 +- web/app.fluidity.money/app/root.tsx | 2 +- .../$network/dashboard/airdrop/index.tsx | 47 ++-- .../app/routes/$network/dashboard/home.tsx | 11 +- .../$network/dashboard/rewards/index.tsx | 45 ++-- .../$network/query/dashboard/airdrop.tsx | 29 ++- .../query/dashboard/airdropLeaderboard.tsx | 11 +- .../routes/$network/query/referralBottles.tsx | 3 +- .../$network/query/userTransactions.tsx | 19 +- .../query/winningUserTransactions.tsx | 6 +- .../app/styles/dashboard.css | 30 ++- .../app/styles/dashboard/airdrop.css | 84 +++++-- .../app/styles/dashboard/airdrop.scss | 5 +- .../app/styles/transfer.css | 15 +- 36 files changed, 470 insertions(+), 309 deletions(-) delete mode 100644 common/ethereum/applications/jumper/jumper.go diff --git a/common/ethereum/applications/jumper/init.go b/common/ethereum/applications/jumper/init.go index 7f0fefc46..872132a0c 100644 --- a/common/ethereum/applications/jumper/init.go +++ b/common/ethereum/applications/jumper/init.go @@ -4,24 +4,4 @@ package jumper -import ( - "strings" - - ethAbi "github.com/ethereum/go-ethereum/accounts/abi" -) - -func init() { - reader := strings.NewReader(jumperSwapAbiAbiStr) - - var err error - - if jumperSwapAbi, err = ethAbi.JSON(reader); err != nil { - panic(err) - } - - reader = strings.NewReader(jumperSwapAbiStr) - - if jumperSwapAbiStr, err = ethAbi.JSON(reader); err != nil { - panic(err) - } -} +func init() {} diff --git a/common/ethereum/applications/jumper/jumper.go b/common/ethereum/applications/jumper/jumper.go deleted file mode 100644 index 0147a6c55..000000000 --- a/common/ethereum/applications/jumper/jumper.go +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright 2022 Fluidity Money. All rights reserved. Use of this -// source code is governed by a GPL-style license that can be found in the -// LICENSE.md file. - -package jumper - -import ( - "fmt" - - ethAbi "github.com/ethereum/go-ethereum/accounts/abi" - ethCommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" -) - -const jumperSwapTopic = "" diff --git a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx index 3d11b0517..1339df2c4 100644 --- a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx +++ b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/index.tsx @@ -1,7 +1,8 @@ - import styles from "./styles.css"; -export const JoeFarmlandsOrCamelotKingdomLinks = () => [{ rel: "stylesheet", href: styles }]; +export const JoeFarmlandsOrCamelotKingdomLinks = () => [ + { rel: "stylesheet", href: styles }, +]; const JoeFarmlandsOrCamelotKingdom = () => { return ( @@ -9,15 +10,17 @@ const JoeFarmlandsOrCamelotKingdom = () => { + src="/images/joe-farmlands.png" + /> + src="/images/kingdom-of-camelot.png" + />
); -} +}; export default JoeFarmlandsOrCamelotKingdom; diff --git a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css index 2e0b9a8ec..2ac505afc 100644 --- a/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css +++ b/web/app.fluidity.money/app/components/JoeFarmlandsOrCamelotKingdom/styles.css @@ -1,4 +1,3 @@ - .joe_farmlands_or_camelot_div { display: grid; padding-top: 20px; @@ -6,7 +5,7 @@ .joe_farmlands_or_camelot_div a { grid-area: 1/1; - --_p: calc(-1*var(--g)); + --_p: calc(-1 * var(--g)); } .joe_farmlands_or_camelot_div img { diff --git a/web/app.fluidity.money/app/queries/addReferralCode.ts b/web/app.fluidity.money/app/queries/addReferralCode.ts index c544833c8..ecb5639f2 100644 --- a/web/app.fluidity.money/app/queries/addReferralCode.ts +++ b/web/app.fluidity.money/app/queries/addReferralCode.ts @@ -40,8 +40,12 @@ const addReferralCode = (address: string, code: string) => { variables, }; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + return jsonPost( - process.env.FLU_HASURA_URL!, + url, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts b/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts index 155de2069..c85fc0391 100644 --- a/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts +++ b/web/app.fluidity.money/app/queries/useAirdropLeaderboard.ts @@ -1,10 +1,7 @@ import { jsonPost, gql, fetchInternalEndpoint } from "~/util"; const queryByUserAllTime = gql` - query AirdropLeaderboard( - $epoch: lootbox_epoch! - $address: String! - ) { + query AirdropLeaderboard($epoch: lootbox_epoch!, $address: String!) { airdrop_leaderboard(where: { address: { _eq: $address } }, limit: 1) { user: address rank @@ -17,12 +14,11 @@ const queryByUserAllTime = gql` `; const queryAllTime = gql` - query AirdropLeaderboard( - $epoch: lootbox_epoch! - ) { + query AirdropLeaderboard($epoch: lootbox_epoch!) { airdrop_leaderboard( args: { epoch_: $epoch } - limit: 16, order_by: { total_lootboxes: desc } + limit: 16 + order_by: { total_lootboxes: desc } ) { user: address rank @@ -37,10 +33,7 @@ const queryAllTime = gql` `; const queryByUser24Hours = gql` - query AirdropLeaderboard( - $epoch: lootbox_epoch! - $address: String! - ) { + query AirdropLeaderboard($epoch: lootbox_epoch!, $address: String!) { airdrop_leaderboard: airdrop_leaderboard_24_hours( args: { epoch_: $epoch, application_: $application } where: { address: { _eq: $address } } @@ -163,7 +156,10 @@ type AirdropLeaderboardResponse = { errors?: unknown; }; -export const useAirdropLeaderboardByUserAllTime = (epoch: string, address: string) => { +export const useAirdropLeaderboardByUserAllTime = ( + epoch: string, + address: string +) => { const { url, headers } = fetchInternalEndpoint(); const variables = { @@ -197,12 +193,15 @@ export const useAirdropLeaderboardAllTime = (epoch: string) => { ); }; -export const useAirdropLeaderboardByUser24Hours = (epoch: string, address: string) => { +export const useAirdropLeaderboardByUser24Hours = ( + epoch: string, + address: string +) => { const { url, headers } = fetchInternalEndpoint(); const variables = { address, - epoch + epoch, }; const body = { query: queryByUser24Hours, diff --git a/web/app.fluidity.money/app/queries/useAirdropStats.ts b/web/app.fluidity.money/app/queries/useAirdropStats.ts index b100db678..f712c4d77 100644 --- a/web/app.fluidity.money/app/queries/useAirdropStats.ts +++ b/web/app.fluidity.money/app/queries/useAirdropStats.ts @@ -29,7 +29,10 @@ const queryAirdropStatsByAddress = gql` } `; -export const useAirdropStatsByAddress = async (address: string, epoch: string) => { +export const useAirdropStatsByAddress = async ( + address: string, + epoch: string +) => { const { url, headers } = fetchInternalEndpoint(); const variables = { diff --git a/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts b/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts index 23708c247..834839794 100644 --- a/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts @@ -41,7 +41,11 @@ const useApplicationRewardStatistics = async ( network: T | string ) => { const variables = { network }; - const url = process.env.FLU_HASURA_URL!; + + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + const body = { variables, query: query, diff --git a/web/app.fluidity.money/app/queries/useAssetStatistics.ts b/web/app.fluidity.money/app/queries/useAssetStatistics.ts index 887e7c889..ecaec584e 100644 --- a/web/app.fluidity.money/app/queries/useAssetStatistics.ts +++ b/web/app.fluidity.money/app/queries/useAssetStatistics.ts @@ -86,10 +86,12 @@ const useAssetStatistics = ( }, }; - const fluGqlEndpoint = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); return jsonPost( - fluGqlEndpoint, + url, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts b/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts index 06345c435..b7e854821 100644 --- a/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts @@ -19,7 +19,9 @@ const query = gql` const useGlobalRewardStatistics = async (network: string) => { const variables = { network }; - const url = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); const body = { variables, query: query, diff --git a/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts b/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts index d39a9150e..7e90a0e5d 100644 --- a/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts @@ -76,7 +76,9 @@ const useHighestRewardStatisticsByNetwork = async (network: string) => { } const variables = { network }; - const url = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); const body = { variables, query: queryByNetwork, @@ -102,7 +104,9 @@ type HighestRewardAllBody = { }; const useHighestRewardStatisticsAll = async () => { - const url = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); const body = { query: queryAll, }; diff --git a/web/app.fluidity.money/app/queries/useLootBottles.ts b/web/app.fluidity.money/app/queries/useLootBottles.ts index fabc36bef..151c7e980 100644 --- a/web/app.fluidity.money/app/queries/useLootBottles.ts +++ b/web/app.fluidity.money/app/queries/useLootBottles.ts @@ -41,8 +41,12 @@ const useLootboxesByTxHash = (filterHashes: string[]) => { variables, }; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + return jsonPost( - process.env.FLU_HASURA_URL!, + url, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useLootboxConfig.ts b/web/app.fluidity.money/app/queries/useLootboxConfig.ts index 3fe61a3fc..e2aed0dc1 100644 --- a/web/app.fluidity.money/app/queries/useLootboxConfig.ts +++ b/web/app.fluidity.money/app/queries/useLootboxConfig.ts @@ -3,12 +3,12 @@ import { jsonPost, gql, fetchInternalEndpoint } from "~/util"; const queryGetConfigCurrentProgram = gql` query getLootboxConfig { lootboxConfig: lootbox_config( - where: { is_current_program: { _eq: true }} + where: { is_current_program: { _eq: true } } limit: 1 ) { - programBegin: program_begin, - programEnd: program_end, - epochIdentifier: epoch_identifier, + programBegin: program_begin + programEnd: program_end + epochIdentifier: epoch_identifier ethereumApplication: ethereum_application } } @@ -17,12 +17,12 @@ const queryGetConfigCurrentProgram = gql` const queryGetConfigSpecific = gql` query getLootboxConfig($identifier: lootbox_epoch!) { lootboxConfig: lootbox_config( - where: { epoch_identifier: { _eq: $identifier }} + where: { epoch_identifier: { _eq: $identifier } } limit: 1 ) { - programBegin: program_begin, - programEnd: program_end, - epochIdentifier: epoch_identifier, + programBegin: program_begin + programEnd: program_end + epochIdentifier: epoch_identifier ethereumApplication: ethereum_application } } @@ -52,21 +52,21 @@ type IUseLootboxConfig = { shouldFind: boolean | undefined; }; -export const useLootboxConfig = ({ identifier, shouldFind }: IUseLootboxConfig) => { +export const useLootboxConfig = ({ + identifier, + shouldFind, +}: IUseLootboxConfig) => { const { url, headers } = fetchInternalEndpoint(); const body = (() => - shouldFind ? { - query: queryGetConfigCurrentProgram - } : { - query: queryGetConfigSpecific, - variables: { identifier } - } - )(); + shouldFind + ? { + query: queryGetConfigCurrentProgram, + } + : { + query: queryGetConfigSpecific, + variables: { identifier }, + })(); - return jsonPost( - url, - body, - headers - ); + return jsonPost(url, body, headers); }; diff --git a/web/app.fluidity.money/app/queries/useReferralCount.ts b/web/app.fluidity.money/app/queries/useReferralCount.ts index 5ccb96994..461764f75 100644 --- a/web/app.fluidity.money/app/queries/useReferralCount.ts +++ b/web/app.fluidity.money/app/queries/useReferralCount.ts @@ -64,8 +64,12 @@ const useActiveReferralCountByReferrerAddress = (address: string) => { variables, }; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + return jsonPost( - process.env.FLU_HASURA_URL!, + url, body, process.env.FLU_HASURA_SECRET ? { @@ -85,8 +89,12 @@ const useActiveReferralCountByRefereeAddress = (address: string) => { variables, }; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + return jsonPost( - process.env.FLU_HASURA_URL!, + url, body, process.env.FLU_HASURA_SECRET ? { @@ -106,8 +114,12 @@ const useInactiveReferralCountByRefereeAddress = (address: string) => { variables, }; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + return jsonPost( - process.env.FLU_HASURA_URL!, + url, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useReferrals.ts b/web/app.fluidity.money/app/queries/useReferrals.ts index c1acd60d1..5c49c1e23 100644 --- a/web/app.fluidity.money/app/queries/useReferrals.ts +++ b/web/app.fluidity.money/app/queries/useReferrals.ts @@ -71,8 +71,12 @@ const useReferralByAddress = (referrer: string, referee: string) => { variables, }; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + return jsonPost( - process.env.FLU_HASURA_URL!, + url, body, process.env.FLU_HASURA_SECRET ? { @@ -92,8 +96,12 @@ const useInactiveReferralByAddress = (address: string) => { variables, }; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + return jsonPost( - process.env.FLU_HASURA_URL!, + url, body, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useStakingData.ts b/web/app.fluidity.money/app/queries/useStakingData.ts index 0bc783fdb..8f2e9d9b2 100644 --- a/web/app.fluidity.money/app/queries/useStakingData.ts +++ b/web/app.fluidity.money/app/queries/useStakingData.ts @@ -24,7 +24,11 @@ export const useStakingDataByAddress = async ( address: `0x${"0".repeat(24)}${address.slice(2)}`, days_elapsed: daysElapsed, }; - const url = process.env.FLU_HASURA_URL!; + + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + const body = { variables, query: queryStakingDataByAddress, diff --git a/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts b/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts index 6429188e1..f6c224e0b 100644 --- a/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts @@ -42,7 +42,9 @@ const query = gql` const useTokenRewardStatistics = async (network: Chain | string) => { const variables = { network }; - const url = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); const body = { variables, query: query, diff --git a/web/app.fluidity.money/app/queries/useTokens.ts b/web/app.fluidity.money/app/queries/useTokens.ts index b36d29cf3..aaf1b6b2b 100644 --- a/web/app.fluidity.money/app/queries/useTokens.ts +++ b/web/app.fluidity.money/app/queries/useTokens.ts @@ -23,10 +23,14 @@ export type Asset = { }; export const useTokens = async () => { + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + const { data: { asset }, } = await jsonPost( - process.env.FLU_HASURA_URL!, + url, { query: tokenQuery }, process.env.FLU_HASURA_SECRET ? { diff --git a/web/app.fluidity.money/app/queries/useUserActionsAggregate.ts b/web/app.fluidity.money/app/queries/useUserActionsAggregate.ts index b574c4f43..7f037e802 100644 --- a/web/app.fluidity.money/app/queries/useUserActionsAggregate.ts +++ b/web/app.fluidity.money/app/queries/useUserActionsAggregate.ts @@ -16,124 +16,143 @@ export type AggregatedTransaction = Omit< const queryByAddress: Queryable = { arbitrum: gql` - query AggregatedUserTransactionsByAddress($offset: Int = 0, $limit: Int = 12, $address: String!, $token: String) { - arbitrum: aggregated_user_transactions_lootbottles( - order_by: {time: desc}, - limit: $limit, - offset: $offset, - where: { - network: {_eq: "arbitrum"} - token_short_name: {_eq: $token}, - type: {_is_null: false}, - _or: [ - {sender_address: {_eq: $address}}, - {recipient_address: {_eq: $address}} - ] - } + query AggregatedUserTransactionsByAddress( + $offset: Int = 0 + $limit: Int = 12 + $address: String! + $token: String ) { - value: amount - application - network - receiver: recipient_address - rewardHash: reward_hash - sender: sender_address - swap_in - timestamp: time - currency: token_short_name - hash: transaction_hash - type - utility_amount - utility_name - winner: winning_address - reward: winning_amount - rewardTier: reward_tier - lootboxCount: lootbox_count + arbitrum: aggregated_user_transactions_lootbottles( + order_by: { time: desc } + limit: $limit + offset: $offset + where: { + network: { _eq: "arbitrum" } + token_short_name: { _eq: $token } + type: { _is_null: false } + _or: [ + { sender_address: { _eq: $address } } + { recipient_address: { _eq: $address } } + ] + } + ) { + value: amount + application + network + receiver: recipient_address + rewardHash: reward_hash + sender: sender_address + swap_in + timestamp: time + currency: token_short_name + hash: transaction_hash + type + utility_amount + utility_name + winner: winning_address + reward: winning_amount + rewardTier: reward_tier + lootboxCount: lootbox_count + } } - } `, solana: gql` - query AggregatedUserTransactionsByAddress($offset: Int = 0, $limit: Int = 12, $address: String!) { - solana: aggregated_user_transactions_lootbottles( - order_by: {time: desc}, - limit: $limit, - offset: $offset, - where: { - network: {_eq: "solana"} - type: {_is_null: false}, - _or: [ - {sender_address: {_eq: $address}}, - {recipient_address: {_eq: $address}} - ] - } + query AggregatedUserTransactionsByAddress( + $offset: Int = 0 + $limit: Int = 12 + $address: String! ) { - value: amount - application - network - receiver: recipient_address - rewardHash: reward_hash - sender: sender_address - swap_in - timestamp: time - currency: token_short_name - hash: transaction_hash - type - utility_amount - utility_name - winner: winning_address - reward: winning_amount - rewardTier: reward_tier - lootboxCount: lootbox_count + solana: aggregated_user_transactions_lootbottles( + order_by: { time: desc } + limit: $limit + offset: $offset + where: { + network: { _eq: "solana" } + type: { _is_null: false } + _or: [ + { sender_address: { _eq: $address } } + { recipient_address: { _eq: $address } } + ] + } + ) { + value: amount + application + network + receiver: recipient_address + rewardHash: reward_hash + sender: sender_address + swap_in + timestamp: time + currency: token_short_name + hash: transaction_hash + type + utility_amount + utility_name + winner: winning_address + reward: winning_amount + rewardTier: reward_tier + lootboxCount: lootbox_count + } } - } `, }; const queryAll: Queryable = { arbitrum: gql` - query aggregatedUserTransactionsAll ($offset: Int = 0, $limit: Int = 12) { - arbitrum: aggregated_user_transactions_lootbottles(order_by: {time: desc}, limit: $limit, offset: $offset, where: {network: {_eq: "arbitrum"}, type: {_is_null: false}}) { - value: amount - application - network - receiver: recipient_address - rewardHash: reward_hash - sender: sender_address - swap_in - timestamp: time - currency: token_short_name - hash: transaction_hash - type - utility_amount - utility_name - winner: winning_address - reward: winning_amount - rewardTier: reward_tier - lootboxCount: lootbox_count + query aggregatedUserTransactionsAll($offset: Int = 0, $limit: Int = 12) { + arbitrum: aggregated_user_transactions_lootbottles( + order_by: { time: desc } + limit: $limit + offset: $offset + where: { network: { _eq: "arbitrum" }, type: { _is_null: false } } + ) { + value: amount + application + network + receiver: recipient_address + rewardHash: reward_hash + sender: sender_address + swap_in + timestamp: time + currency: token_short_name + hash: transaction_hash + type + utility_amount + utility_name + winner: winning_address + reward: winning_amount + rewardTier: reward_tier + lootboxCount: lootbox_count + } } - } `, solana: gql` - query aggregatedUserTransactionsAll ($offset: Int = 0, $limit: Int = 12) { - solana: aggregated_user_transactions_lootbottles(order_by: {time: desc}, limit: $limit, offset: $offset, where: {network: {_eq: "solana"}, type: {_is_null: false}}) { - value: amount - application - network - receiver: recipient_address - rewardHash: reward_hash - sender: sender_address - swap_in - timestamp: time - currency: token_short_name - hash: transaction_hash - type - utility_amount - utility_name - winner: winning_address - reward: winning_amount - rewardTier: reward_tier - lootboxCount: lootbox_count + query aggregatedUserTransactionsAll($offset: Int = 0, $limit: Int = 12) { + solana: aggregated_user_transactions_lootbottles( + order_by: { time: desc } + limit: $limit + offset: $offset + where: { network: { _eq: "solana" }, type: { _is_null: false } } + ) { + value: amount + application + network + receiver: recipient_address + rewardHash: reward_hash + sender: sender_address + swap_in + timestamp: time + currency: token_short_name + hash: transaction_hash + type + utility_amount + utility_name + winner: winning_address + reward: winning_amount + rewardTier: reward_tier + lootboxCount: lootbox_count + } } - } `, }; diff --git a/web/app.fluidity.money/app/queries/useUserRewards.ts b/web/app.fluidity.money/app/queries/useUserRewards.ts index 96722797b..9f486677d 100644 --- a/web/app.fluidity.money/app/queries/useUserRewards.ts +++ b/web/app.fluidity.money/app/queries/useUserRewards.ts @@ -177,7 +177,9 @@ const useUserRewardsAll = async (network: string) => { const variables = { network, }; - const url = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); const body = { variables, query: queryWinnersAll[network as Chain], @@ -196,7 +198,11 @@ const useUserRewardsAll = async (network: string) => { const useUserRewardsByAddress = async (network: string, address: string) => { const variables = { network, address }; - const url = process.env.FLU_HASURA_URL!; + + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); + const body = { variables, query: queryWinnersByAddress[network as Chain], @@ -217,7 +223,9 @@ const useUserPendingRewardsAll = async (network: string) => { const variables = { network, }; - const url = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); const body = { variables, query: queryPendingWinnersAll, @@ -239,7 +247,9 @@ const useUserPendingRewardsByAddress = async ( address: string ) => { const variables = { network, address }; - const url = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); const body = { variables, query: queryPendingWinnersByAddress, diff --git a/web/app.fluidity.money/app/queries/useUserTransactions.ts b/web/app.fluidity.money/app/queries/useUserTransactions.ts index c5f47aa71..8db0ae4f9 100644 --- a/web/app.fluidity.money/app/queries/useUserTransactions.ts +++ b/web/app.fluidity.money/app/queries/useUserTransactions.ts @@ -565,7 +565,7 @@ const parseHasuraUserTransactions = ( }, application: transfer.application, lootboxCount: transfer.lootboxCount, - rewardTier: transfer.rewardTier + rewardTier: transfer.rewardTier, }; }), }, diff --git a/web/app.fluidity.money/app/queries/useUserYield.ts b/web/app.fluidity.money/app/queries/useUserYield.ts index b3b09f556..7d500625a 100644 --- a/web/app.fluidity.money/app/queries/useUserYield.ts +++ b/web/app.fluidity.money/app/queries/useUserYield.ts @@ -95,7 +95,9 @@ type UserYieldByAddressBody = { const useUserYieldAll = async (network: string) => { const variables = { network }; - const url = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); const body = { variables, query: queryAll, @@ -114,7 +116,9 @@ const useUserYieldAll = async (network: string) => { const useUserYieldByAddress = async (network: string, address: string) => { const variables = { network, address }; - const url = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); const body = { variables, query: queryByAddress, diff --git a/web/app.fluidity.money/app/queries/useVolumeStats.ts b/web/app.fluidity.money/app/queries/useVolumeStats.ts index b799aa0e4..1071ee284 100644 --- a/web/app.fluidity.money/app/queries/useVolumeStats.ts +++ b/web/app.fluidity.money/app/queries/useVolumeStats.ts @@ -120,7 +120,9 @@ const useVolumeStatsByAddress = async (network: string, address: string) => { query: queryVolumeByAddress, }; - const url = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); return await jsonPost( url, @@ -143,7 +145,9 @@ const useVolumeStats = async (network: string) => { query: queryVolume, }; - const url = process.env.FLU_HASURA_URL!; + const url = process.env.FLU_HASURA_URL; + + if (!url) throw new Error("FLU_HASURA_URL not set!"); return await jsonPost( url, diff --git a/web/app.fluidity.money/app/root.tsx b/web/app.fluidity.money/app/root.tsx index 323475f24..226392f24 100644 --- a/web/app.fluidity.money/app/root.tsx +++ b/web/app.fluidity.money/app/root.tsx @@ -15,7 +15,7 @@ import { withSentry } from "@sentry/remix"; import globalStylesheetUrl from "./global-styles.css"; import surfingStylesheetUrl from "@fluidity-money/surfing/dist/style.css"; -import { JoeFarmlandsOrCamelotKingdomLinks,ToolTipLinks } from "./components"; +import { JoeFarmlandsOrCamelotKingdomLinks, ToolTipLinks } from "./components"; import { ToolProvider } from "./components/ToolTip"; import { SplitContextProvider } from "contexts/SplitProvider"; import CacheProvider from "contexts/CacheProvider"; diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx index d3fd7cf86..de8f93ecc 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx @@ -122,7 +122,7 @@ const SAFE_DEFAULT_AIRDROP: AirdropLoaderData = { epochIdentifier: "epoch_1", ethereumApplication: "none", epochFound: false, - loaded: false + loaded: false, }; const SAFE_DEFAULT_AIRDROP_LEADERBOARD: AirdropLeaderboardLoaderData = { @@ -169,7 +169,8 @@ const Airdrop = () => { Airdrop - Wrap, Transact and Earn using $fUSDC, provide liquidity for even more rewards! + Wrap, Transact and Earn using $fUSDC, provide liquidity for even more + rewards!
); @@ -214,7 +215,9 @@ const Airdrop = () => { const isMobile = width < mobileBreakpoint; const { data: airdropData } = useCache( - address ? `/${network}/query/dashboard/airdrop?address=${address}&epoch=${EPOCH_CURRENT_IDENTIFIER}` : "" + address + ? `/${network}/query/dashboard/airdrop?address=${address}&epoch=${EPOCH_CURRENT_IDENTIFIER}` + : "" ); const { data: airdropLeaderboardData } = useCache( @@ -226,12 +229,16 @@ const Airdrop = () => { ); const { data: referralData } = useCache( - address ? `/${network}/query/referrals?address=${address}&epoch=${EPOCH_CURRENT_IDENTIFIER}` : "" + address + ? `/${network}/query/referrals?address=${address}&epoch=${EPOCH_CURRENT_IDENTIFIER}` + : "" ); const { data: referralLootboxData } = useCache( - address ? `/${network}/query/referralBottles?address=${address}&epoch=${EPOCH_CURRENT_IDENTIFIER}` : "" + address + ? `/${network}/query/referralBottles?address=${address}&epoch=${EPOCH_CURRENT_IDENTIFIER}` + : "" ); const data = { @@ -293,14 +300,7 @@ const Airdrop = () => { setCurrentModal(isAirdropModal(destModal) ? destModal : null); }, [location.hash]); - const [stakes, _] = useState< - Array<{ - fluidAmount: BN; - baseAmount: BN; - durationDays: number; - depositDate: Date; - }> - >([]); + const stakes = []; const fetchUserTokenBalance = async () => { const userTokenBalance = await Promise.all( @@ -557,11 +557,12 @@ const Airdrop = () => { > Testnet Rewards - - + + Dune @@ -902,7 +903,7 @@ const Airdrop = () => { borderRadius: "10px", borderStyle: "solid", borderWidth: "1px", - borderColor: "white" + borderColor: "white", }} width="100%" src="/images/epoch2AirdropBanner.png" @@ -1161,7 +1162,7 @@ const MultiplierTasks = () => { { provider: "Jumper", link: "https://app.uniswap.org/#/swap" }, { provider: "Uniswap", - link: "https://app.uniswap.org/#/swap" + link: "https://app.uniswap.org/#/swap", }, { provider: "Trader Joe", link: "https://app.camelot.exchange/" }, { provider: "Camelot", link: "https://saddle.exchange/#/" }, @@ -1269,10 +1270,6 @@ interface IMyMultiplier { const MyMultiplier = ({ seeMyStakingStats, - seeStakeNow, - stakes, - wethPrice, - usdcPrice, isMobile = false, }: IMyMultiplier) => { return ( @@ -1469,7 +1466,7 @@ const Leaderboard = ({ bottles: 0, highestRewardTier: 0, fusdcEarned: 0, - arbEarned: 0 + arbEarned: 0, }; data.push(userEntry); diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx index 9487d7a32..0539d1cba 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/home.tsx @@ -378,7 +378,7 @@ export default function Home() { utilityTokens, application, rewardTier, - lootboxCount + lootboxCount, } = data; const appProviderName = getProviderDisplayName(application); @@ -460,7 +460,8 @@ export default function Home() { ); case "BOTTLES EARNED": return ( - { lootboxCount ? ( + + {lootboxCount ? ( ) : ( - - ) - } - ) + )}{" "} + + ); case "ACCOUNT": return ( diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/rewards/index.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/rewards/index.tsx index cfd57d002..a9d1ab7a5 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/rewards/index.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/rewards/index.tsx @@ -38,7 +38,7 @@ import { WalletIcon, TabButton, toDecimalPlaces, - LootBottle + LootBottle, } from "@fluidity-money/surfing"; import { useContext, useEffect, useState, useMemo } from "react"; import { ToolTipContent, useToolTip, UtilityToken } from "~/components"; @@ -435,7 +435,7 @@ export default function Rewards() { utilityTokens, application, lootboxCount, - rewardTier + rewardTier, } = data; const toolTip = useToolTip(); @@ -543,7 +543,8 @@ export default function Rewards() { ); case "BOTTLES EARNED": return ( - { lootboxCount ? ( + + {lootboxCount ? ( ) : ( - - ) - } + )}{" "} + ); case "WINNER": return ( @@ -650,23 +651,23 @@ export default function Rewards() {
- { network == "arbitrum" ? - <> - + {network == "arbitrum" ? ( + <> + - - - - - - - - - - - - : - <> + + + + + + + + + + + + ) : ( + <> @@ -680,7 +681,7 @@ export default function Rewards() { - } + )}
Swap To Earn {!isMobile && Swap Fluid Assets to generate yield.} diff --git a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx index 714546e9c..5a0685b79 100644 --- a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdrop.tsx @@ -56,11 +56,12 @@ export const loader: LoaderFunction = async ({ params, request }) => { const address = address_?.toLowerCase(); - if (!address || !network || !epochIdentifier) throw new Error("Invalid Request"); + if (!address || !network || !epochIdentifier) + throw new Error("Invalid Request"); const { data, errors } = await useLootboxConfig({ identifier: epochIdentifier, - shouldFind: false + shouldFind: false, }); if (errors) { @@ -90,13 +91,15 @@ export const loader: LoaderFunction = async ({ params, request }) => { programBegin: programBegin_, programEnd: programEnd_, ethereumApplication, - found: epochFound + found: epochFound, } = configs[0]; const programBegin = new Date(programBegin_); const programEnd = new Date(programEnd_); - const epochDaysTotal = Math.round((programEnd.valueOf() - programBegin.valueOf()) / (1000 * 60 * 60 * 24)); + const epochDaysTotal = Math.round( + (programEnd.valueOf() - programBegin.valueOf()) / (1000 * 60 * 60 * 24) + ); const epochDaysElapsed = dayDifference(new Date(), programBegin) % epochDaysTotal; @@ -108,13 +111,15 @@ export const loader: LoaderFunction = async ({ params, request }) => { config.contract.eac_aggregator_proxy[network as Chain]; try { - const [ - { data: airdropStatsData, errors: airdropStatsErrors }, - wethPrice, - ] = await Promise.all([ - useAirdropStatsByAddress(address, epochIdentifier), - getWethUsdPrice(provider, eacAggregatorProxyAddr, EACAggregatorProxyAbi), - ]); + const [{ data: airdropStatsData, errors: airdropStatsErrors }, wethPrice] = + await Promise.all([ + useAirdropStatsByAddress(address, epochIdentifier), + getWethUsdPrice( + provider, + eacAggregatorProxyAddr, + EACAggregatorProxyAbi + ), + ]); if (airdropStatsErrors || !airdropStatsData) throw airdropStatsErrors; @@ -151,7 +156,7 @@ export const loader: LoaderFunction = async ({ params, request }) => { epochDaysElapsed, epochIdentifier, epochFound, - ethereumApplication + ethereumApplication, } satisfies AirdropLoaderData); } catch (err) { captureException(new Error(`Could not fetch airdrop data: ${err}`), { diff --git a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx index 322fbf201..044c8fff0 100644 --- a/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/dashboard/airdropLeaderboard.tsx @@ -44,7 +44,8 @@ export const loader: LoaderFunction = async ({ params, request }) => { case useAll: { return [ () => useAirdropLeaderboardAllTime(epoch), - (address: string) => useAirdropLeaderboardByUserAllTime(epoch, address), + (address: string) => + useAirdropLeaderboardByUserAllTime(epoch, address), ]; } case use24Hours && !!provider: { @@ -62,13 +63,15 @@ export const loader: LoaderFunction = async ({ params, request }) => { default: { return [ () => useAirdropLeaderboard24Hours(epoch), - (address: string) => useAirdropLeaderboardByUser24Hours(epoch, address), + (address: string) => + useAirdropLeaderboardByUser24Hours(epoch, address), ]; } } })(); - const { data: globalLeaderboardData, errors: globalLeaderboardErrors } = await useAllQuery(); + const { data: globalLeaderboardData, errors: globalLeaderboardErrors } = + await useAllQuery(); if (!globalLeaderboardData || globalLeaderboardErrors) throw globalLeaderboardErrors; @@ -111,7 +114,7 @@ export const loader: LoaderFunction = async ({ params, request }) => { bottles: 0, highestRewardTier: 0, fusdcEarned: 0, - arbEarned: 0 + arbEarned: 0, } satisfies AirdropLeaderboardEntry, ] ).concat(leaderboard); diff --git a/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx b/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx index 820ec2029..d6c89b4c3 100644 --- a/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/referralBottles.tsx @@ -19,8 +19,7 @@ export const loader: LoaderFunction = async ({ request }) => { const address = address_.toLocaleLowerCase(); - if (!address || !epoch) - throw new Error("Invalid Request"); + if (!address || !epoch) throw new Error("Invalid Request"); const { data: referralBottleCountData, errors: referralBottleCountErr } = await useReferralLootboxesByAddress(epoch, address); diff --git a/web/app.fluidity.money/app/routes/$network/query/userTransactions.tsx b/web/app.fluidity.money/app/routes/$network/query/userTransactions.tsx index fa1581721..2000c80a1 100644 --- a/web/app.fluidity.money/app/routes/$network/query/userTransactions.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/userTransactions.tsx @@ -120,7 +120,7 @@ export const loader: LoaderFunction = async ({ params, request }) => { type, swap_in, rewardTier, - lootboxCount + lootboxCount, }) => { const utilityName = utility_name?.match(ALPHA_NUMERIC)?.[0]; @@ -146,16 +146,17 @@ export const loader: LoaderFunction = async ({ params, request }) => { // convert to JS timestamp timestamp: new Date(timestamp + "Z").getTime(), value, - currency: 'f' + currency, + currency: "f" + currency, application, swapType, provider: application ?? "Fluidity", logo: tokenLogoMap[currency] || defaultLogo, - utilityTokens: utilityName && utility_amount > 0 - ? { [utilityName]: utility_amount } - : undefined, + utilityTokens: + utilityName && utility_amount > 0 + ? { [utilityName]: utility_amount } + : undefined, rewardTier, - lootboxCount + lootboxCount, }; } ); @@ -358,7 +359,7 @@ export const loader: LoaderFunction = async ({ params, request }) => { currency: { symbol: currency }, application, lootboxCount, - rewardTier + rewardTier, } = transaction; return { @@ -376,7 +377,7 @@ export const loader: LoaderFunction = async ({ params, request }) => { currency, application, lootboxCount, - rewardTier + rewardTier, }; } ); @@ -419,7 +420,7 @@ export const loader: LoaderFunction = async ({ params, request }) => { utilityTokens: winner?.utility, application: tx.application, rewardTier: tx.rewardTier, - lootboxCount: tx.lootboxCount + lootboxCount: tx.lootboxCount, }; }); diff --git a/web/app.fluidity.money/app/routes/$network/query/winningUserTransactions.tsx b/web/app.fluidity.money/app/routes/$network/query/winningUserTransactions.tsx index 2f46d500d..7380b3d3e 100644 --- a/web/app.fluidity.money/app/routes/$network/query/winningUserTransactions.tsx +++ b/web/app.fluidity.money/app/routes/$network/query/winningUserTransactions.tsx @@ -209,7 +209,7 @@ export const loader: LoaderFunction = async ({ params, request }) => { currency: { symbol: currency }, application, lootboxCount, - rewardTier + rewardTier, } = transaction; return { @@ -227,7 +227,7 @@ export const loader: LoaderFunction = async ({ params, request }) => { currency, application, lootboxCount, - rewardTier + rewardTier, }; } ); @@ -293,7 +293,7 @@ export const loader: LoaderFunction = async ({ params, request }) => { utilityTokens: winner.utility, application: tx.application, lootboxCount: tx.lootboxCount, - rewardTier: tx.rewardTier + rewardTier: tx.rewardTier, }; }); diff --git a/web/app.fluidity.money/app/styles/dashboard.css b/web/app.fluidity.money/app/styles/dashboard.css index 443d14bf4..7d3166ba0 100644 --- a/web/app.fluidity.money/app/styles/dashboard.css +++ b/web/app.fluidity.money/app/styles/dashboard.css @@ -149,7 +149,20 @@ body { background-repeat: no-repeat; background-size: 100%; background-position: 0 0, 100% 0, 100% 100%, 0 100%; - background-image: linear-gradient(45deg, #f3b8d8, #b793e9, #9fd4f3, #ffd2c4, #fbf3f3, #d9abdf, #af9ce3, #aae4e1, #c6ead0, #ffffff, #fdb5e4); + background-image: linear-gradient( + 45deg, + #f3b8d8, + #b793e9, + #9fd4f3, + #ffd2c4, + #fbf3f3, + #d9abdf, + #af9ce3, + #aae4e1, + #c6ead0, + #ffffff, + #fdb5e4 + ); animation: rotate 4s linear infinite; } @@ -617,7 +630,20 @@ ul.sidebar-nav li div.active { } .holo { - background: conic-gradient(from 209.59deg at 50% 50%, #f3b8d8 0deg, #b793e9 50.06deg, #9fd4f3 85.94deg, #ffd2c4 134.97deg, #fbf3f3 172.05deg, #d9abdf 200.75deg, #af9ce3 224.67deg, #aae4e1 259.36deg, #c6ead0 298.82deg, #ffffff 328.72deg, #fdb5e4 360deg); + background: conic-gradient( + from 209.59deg at 50% 50%, + #f3b8d8 0deg, + #b793e9 50.06deg, + #9fd4f3 85.94deg, + #ffd2c4 134.97deg, + #fbf3f3 172.05deg, + #d9abdf 200.75deg, + #af9ce3 224.67deg, + #aae4e1 259.36deg, + #c6ead0 298.82deg, + #ffffff 328.72deg, + #fdb5e4 360deg + ); height: 40px; width: 40px; border-radius: 50%; diff --git a/web/app.fluidity.money/app/styles/dashboard/airdrop.css b/web/app.fluidity.money/app/styles/dashboard/airdrop.css index 5a30df300..4e0b8e444 100644 --- a/web/app.fluidity.money/app/styles/dashboard/airdrop.css +++ b/web/app.fluidity.money/app/styles/dashboard/airdrop.css @@ -273,7 +273,19 @@ } .transaction-table > thead > tr.highlighted-row, .transaction-table > tbody > tr.airdrop-row.highlighted-row { - background: linear-gradient(90deg, #f3b8d8 0%, #b793e9 15.1%, #9fd4f3 26.04%, #ffd2c4 36.46%, #fbf3f3 46.88%, #d9abdf 57.29%, #af9ce3 72.4%, #aae4e1 85.42%, #c6ead0 93.23%, #fdb5e4 100%); + background: linear-gradient( + 90deg, + #f3b8d8 0%, + #b793e9 15.1%, + #9fd4f3 26.04%, + #ffd2c4 36.46%, + #fbf3f3 46.88%, + #d9abdf 57.29%, + #af9ce3 72.4%, + #aae4e1 85.42%, + #c6ead0 93.23%, + #fdb5e4 100% + ); } .transaction-table > thead > tr.highlighted-row td, .transaction-table > tbody > tr.airdrop-row.highlighted-row td { @@ -302,14 +314,30 @@ } .airdrop-leaderboard-mobile .transaction-table > thead > tr td:first-child, .airdrop-leaderboard-mobile .transaction-table > thead > tr th:first-child, -.airdrop-leaderboard-mobile .transaction-table > tbody > tr.airdrop-row td:first-child, -.airdrop-leaderboard-mobile .transaction-table > tbody > tr.airdrop-row th:first-child { +.airdrop-leaderboard-mobile + .transaction-table + > tbody + > tr.airdrop-row + td:first-child, +.airdrop-leaderboard-mobile + .transaction-table + > tbody + > tr.airdrop-row + th:first-child { padding-left: 1em; } .airdrop-leaderboard-mobile .transaction-table > thead > tr td:last-child, .airdrop-leaderboard-mobile .transaction-table > thead > tr th:last-child, -.airdrop-leaderboard-mobile .transaction-table > tbody > tr.airdrop-row td:last-child, -.airdrop-leaderboard-mobile .transaction-table > tbody > tr.airdrop-row th:last-child { +.airdrop-leaderboard-mobile + .transaction-table + > tbody + > tr.airdrop-row + td:last-child, +.airdrop-leaderboard-mobile + .transaction-table + > tbody + > tr.airdrop-row + th:last-child { padding-right: 1em; } .airdrop-leaderboard-mobile .transaction-table > thead > tr td, @@ -680,7 +708,10 @@ align-items: flex-start; gap: 0.5em; } -.staking-stats-container .staking-stats-stakes-container .stake .stake-multiplier { +.staking-stats-container + .staking-stats-stakes-container + .stake + .stake-multiplier { width: 100%; display: flex; flex-wrap: wrap; @@ -753,18 +784,31 @@ width: 150px; height: 150px; } -.recap-container .recap-hero .recap-hero-text .recap-circle-scroll .recap-circle-scroll-arrow { +.recap-container + .recap-hero + .recap-hero-text + .recap-circle-scroll + .recap-circle-scroll-arrow { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); } -.recap-container .recap-hero .recap-hero-text .recap-circle-scroll .recap-circle-scroll-arrow svg { +.recap-container + .recap-hero + .recap-hero-text + .recap-circle-scroll + .recap-circle-scroll-arrow + svg { fill: none; stroke: white; transform: scale(3); } -.recap-container .recap-hero .recap-hero-text .recap-circle-scroll .recap-circle-scroll-text { +.recap-container + .recap-hero + .recap-hero-text + .recap-circle-scroll + .recap-circle-scroll-text { font-size: 10px; fill: grey; letter-spacing: 0.4em; @@ -856,19 +900,28 @@ /* Track */ /* Handle */ } -.recap-container .recap-stats .recap-bottle-distribution-container::-webkit-scrollbar { +.recap-container + .recap-stats + .recap-bottle-distribution-container::-webkit-scrollbar { height: 10px; } -.recap-container .recap-stats .recap-bottle-distribution-container::-webkit-scrollbar-track { +.recap-container + .recap-stats + .recap-bottle-distribution-container::-webkit-scrollbar-track { background: transparent; border: 1px solid white; border-radius: 5px; } -.recap-container .recap-stats .recap-bottle-distribution-container::-webkit-scrollbar-thumb { +.recap-container + .recap-stats + .recap-bottle-distribution-container::-webkit-scrollbar-thumb { background: white; border-radius: 5px; } -.recap-container .recap-stats .recap-bottle-distribution-container .bottle-container { +.recap-container + .recap-stats + .recap-bottle-distribution-container + .bottle-container { gap: 1em; display: flex; flex-direction: column; @@ -923,7 +976,10 @@ aspect-ratio: 1/1; } -#tutorial, #staking-stats, #bottles-details, #testnet-rewards { +#tutorial, +#staking-stats, +#bottles-details, +#testnet-rewards { position: fixed; } diff --git a/web/app.fluidity.money/app/styles/dashboard/airdrop.scss b/web/app.fluidity.money/app/styles/dashboard/airdrop.scss index c60b47609..f76b7cfbf 100644 --- a/web/app.fluidity.money/app/styles/dashboard/airdrop.scss +++ b/web/app.fluidity.money/app/styles/dashboard/airdrop.scss @@ -1061,7 +1061,10 @@ $holo: linear-gradient( } } -#tutorial, #staking-stats, #bottles-details, #testnet-rewards { +#tutorial, +#staking-stats, +#bottles-details, +#testnet-rewards { position: fixed; } diff --git a/web/app.fluidity.money/app/styles/transfer.css b/web/app.fluidity.money/app/styles/transfer.css index 337cd2928..0d4055653 100644 --- a/web/app.fluidity.money/app/styles/transfer.css +++ b/web/app.fluidity.money/app/styles/transfer.css @@ -276,7 +276,20 @@ body { right: 0; bottom: 0; z-index: 1; - background: conic-gradient(from 209.59deg at 50% 50%, #f3b8d8 0deg, #b793e9 50.06deg, #9fd4f3 85.94deg, #ffd2c4 134.97deg, #fbf3f3 172.05deg, #d9abdf 200.75deg, #af9ce3 224.67deg, #aae4e1 259.36deg, #c6ead0 298.82deg, #ffffff 328.72deg, #fdb5e4 360deg); + background: conic-gradient( + from 209.59deg at 50% 50%, + #f3b8d8 0deg, + #b793e9 50.06deg, + #9fd4f3 85.94deg, + #ffd2c4 134.97deg, + #fbf3f3 172.05deg, + #d9abdf 200.75deg, + #af9ce3 224.67deg, + #aae4e1 259.36deg, + #c6ead0 298.82deg, + #ffffff 328.72deg, + #fdb5e4 360deg + ); filter: blur(10px); scale: 1.1; } From 36e2b5d0d16a498b3e9340363e3b6e29dd7e1a2c Mon Sep 17 00:00:00 2001 From: user Date: Wed, 10 Jan 2024 15:29:52 +1030 Subject: [PATCH 16/18] Add FLU_HASURA_URL to the test ci yaml file --- .github/workflows/test-ci.yml | 1 + web/app.fluidity.money/Dockerfile.frontend | 2 ++ 2 files changed, 3 insertions(+) diff --git a/.github/workflows/test-ci.yml b/.github/workflows/test-ci.yml index 1383af224..71cbc4f93 100644 --- a/.github/workflows/test-ci.yml +++ b/.github/workflows/test-ci.yml @@ -105,6 +105,7 @@ jobs: if: always() env: GITHUB_CONTEXT: ${{ toJson(github) }} + FLU_HASURA_URL: ${{ secrets.FLU_HASURA_URL }} with: command: | flu send-discord --webhook-url ${{ secrets.FLU_CI_DISCORD_WEBHOOK_URL }} --status ${{ job.status }} diff --git a/web/app.fluidity.money/Dockerfile.frontend b/web/app.fluidity.money/Dockerfile.frontend index 7dae8cce9..48aca35d2 100644 --- a/web/app.fluidity.money/Dockerfile.frontend +++ b/web/app.fluidity.money/Dockerfile.frontend @@ -12,6 +12,8 @@ RUN yarn ARG FLU_SENTRY_DSN +ARG FLU_HASURA_URL + WORKDIR /usr/local/src/fluidity/web/app.fluidity.money RUN make frontend From bbe628492356bd78458e6de04b45e4e8dc4c4a94 Mon Sep 17 00:00:00 2001 From: user Date: Wed, 10 Jan 2024 15:51:24 +1030 Subject: [PATCH 17/18] Remove the environment variable for the URL to be replaced another day --- .github/workflows/test-ci.yml | 1 - web/app.fluidity.money/Dockerfile.frontend | 2 -- web/app.fluidity.money/README.md | 5 ----- .../app/queries/addReferral.ts | 4 +--- .../app/queries/addReferralCode.ts | 4 +--- .../queries/useApplicationRewardStatistics.ts | 4 +--- .../app/queries/useAssetStatistics.ts | 4 +--- .../app/queries/useGlobalRewardStatistics.ts | 4 +--- .../app/queries/useHighestRewardStatistics.ts | 8 ++------ .../app/queries/useLootBottles.ts | 4 +--- .../app/queries/useReferralCode.ts | 8 ++------ .../app/queries/useReferralCount.ts | 12 +++--------- .../app/queries/useReferrals.ts | 8 ++------ .../app/queries/useStakingData.ts | 4 +--- .../app/queries/useTokenRewardStatistics.ts | 4 +--- web/app.fluidity.money/app/queries/useTokens.ts | 4 +--- .../app/queries/useUserRewards.ts | 16 ++++------------ .../app/queries/useUserUnclaimedRewards.ts | 4 +--- .../app/queries/useUserYield.ts | 8 ++------ .../app/queries/useVolumeStats.ts | 8 ++------ 20 files changed, 27 insertions(+), 89 deletions(-) diff --git a/.github/workflows/test-ci.yml b/.github/workflows/test-ci.yml index 71cbc4f93..1383af224 100644 --- a/.github/workflows/test-ci.yml +++ b/.github/workflows/test-ci.yml @@ -105,7 +105,6 @@ jobs: if: always() env: GITHUB_CONTEXT: ${{ toJson(github) }} - FLU_HASURA_URL: ${{ secrets.FLU_HASURA_URL }} with: command: | flu send-discord --webhook-url ${{ secrets.FLU_CI_DISCORD_WEBHOOK_URL }} --status ${{ job.status }} diff --git a/web/app.fluidity.money/Dockerfile.frontend b/web/app.fluidity.money/Dockerfile.frontend index 48aca35d2..7dae8cce9 100644 --- a/web/app.fluidity.money/Dockerfile.frontend +++ b/web/app.fluidity.money/Dockerfile.frontend @@ -12,8 +12,6 @@ RUN yarn ARG FLU_SENTRY_DSN -ARG FLU_HASURA_URL - WORKDIR /usr/local/src/fluidity/web/app.fluidity.money RUN make frontend diff --git a/web/app.fluidity.money/README.md b/web/app.fluidity.money/README.md index 824204cf5..38174ccec 100644 --- a/web/app.fluidity.money/README.md +++ b/web/app.fluidity.money/README.md @@ -17,11 +17,6 @@ | `FLU_SENTRY_DSN` | Sentry reporting URI | | `FLU_SPLIT_BROWSER_KEY` | Split Client-Side Key | | `FLU_WALLETCONNECT_ID` | WalletConnect Client-Side Project ID | -| `FLU_HASURA_URL` | Hasura API URL | - -### Note on the Hasura API URL - -This is also set manually in `app/util/api/graphql.ts`. ## Building diff --git a/web/app.fluidity.money/app/queries/addReferral.ts b/web/app.fluidity.money/app/queries/addReferral.ts index 18ad5b588..2222c90c3 100644 --- a/web/app.fluidity.money/app/queries/addReferral.ts +++ b/web/app.fluidity.money/app/queries/addReferral.ts @@ -40,9 +40,7 @@ const addReferral = (referrer: string, referee: string) => { variables, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, diff --git a/web/app.fluidity.money/app/queries/addReferralCode.ts b/web/app.fluidity.money/app/queries/addReferralCode.ts index ecb5639f2..5aba12969 100644 --- a/web/app.fluidity.money/app/queries/addReferralCode.ts +++ b/web/app.fluidity.money/app/queries/addReferralCode.ts @@ -40,9 +40,7 @@ const addReferralCode = (address: string, code: string) => { variables, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, diff --git a/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts b/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts index 834839794..e6252aba7 100644 --- a/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useApplicationRewardStatistics.ts @@ -42,9 +42,7 @@ const useApplicationRewardStatistics = async ( ) => { const variables = { network }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { variables, diff --git a/web/app.fluidity.money/app/queries/useAssetStatistics.ts b/web/app.fluidity.money/app/queries/useAssetStatistics.ts index ecaec584e..366fb6828 100644 --- a/web/app.fluidity.money/app/queries/useAssetStatistics.ts +++ b/web/app.fluidity.money/app/queries/useAssetStatistics.ts @@ -86,9 +86,7 @@ const useAssetStatistics = ( }, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, diff --git a/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts b/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts index b7e854821..8dfd4e666 100644 --- a/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useGlobalRewardStatistics.ts @@ -19,9 +19,7 @@ const query = gql` const useGlobalRewardStatistics = async (network: string) => { const variables = { network }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { variables, query: query, diff --git a/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts b/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts index 7e90a0e5d..05d007bdf 100644 --- a/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useHighestRewardStatistics.ts @@ -76,9 +76,7 @@ const useHighestRewardStatisticsByNetwork = async (network: string) => { } const variables = { network }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { variables, query: queryByNetwork, @@ -104,9 +102,7 @@ type HighestRewardAllBody = { }; const useHighestRewardStatisticsAll = async () => { - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { query: queryAll, }; diff --git a/web/app.fluidity.money/app/queries/useLootBottles.ts b/web/app.fluidity.money/app/queries/useLootBottles.ts index 151c7e980..6f5025298 100644 --- a/web/app.fluidity.money/app/queries/useLootBottles.ts +++ b/web/app.fluidity.money/app/queries/useLootBottles.ts @@ -41,9 +41,7 @@ const useLootboxesByTxHash = (filterHashes: string[]) => { variables, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, diff --git a/web/app.fluidity.money/app/queries/useReferralCode.ts b/web/app.fluidity.money/app/queries/useReferralCode.ts index 4098e0bd5..75db76633 100644 --- a/web/app.fluidity.money/app/queries/useReferralCode.ts +++ b/web/app.fluidity.money/app/queries/useReferralCode.ts @@ -54,9 +54,7 @@ const useReferralCodeByAddress = (address: string) => { variables, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, @@ -79,9 +77,7 @@ const useReferralCodeByCode = (code: string) => { variables, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, diff --git a/web/app.fluidity.money/app/queries/useReferralCount.ts b/web/app.fluidity.money/app/queries/useReferralCount.ts index 461764f75..0a6ed9fec 100644 --- a/web/app.fluidity.money/app/queries/useReferralCount.ts +++ b/web/app.fluidity.money/app/queries/useReferralCount.ts @@ -64,9 +64,7 @@ const useActiveReferralCountByReferrerAddress = (address: string) => { variables, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, @@ -89,9 +87,7 @@ const useActiveReferralCountByRefereeAddress = (address: string) => { variables, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, @@ -114,9 +110,7 @@ const useInactiveReferralCountByRefereeAddress = (address: string) => { variables, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, diff --git a/web/app.fluidity.money/app/queries/useReferrals.ts b/web/app.fluidity.money/app/queries/useReferrals.ts index 5c49c1e23..731f4b8af 100644 --- a/web/app.fluidity.money/app/queries/useReferrals.ts +++ b/web/app.fluidity.money/app/queries/useReferrals.ts @@ -71,9 +71,7 @@ const useReferralByAddress = (referrer: string, referee: string) => { variables, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, @@ -96,9 +94,7 @@ const useInactiveReferralByAddress = (address: string) => { variables, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, diff --git a/web/app.fluidity.money/app/queries/useStakingData.ts b/web/app.fluidity.money/app/queries/useStakingData.ts index 8f2e9d9b2..1d335af2f 100644 --- a/web/app.fluidity.money/app/queries/useStakingData.ts +++ b/web/app.fluidity.money/app/queries/useStakingData.ts @@ -25,9 +25,7 @@ export const useStakingDataByAddress = async ( days_elapsed: daysElapsed, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { variables, diff --git a/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts b/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts index f6c224e0b..ee371c37b 100644 --- a/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts +++ b/web/app.fluidity.money/app/queries/useTokenRewardStatistics.ts @@ -42,9 +42,7 @@ const query = gql` const useTokenRewardStatistics = async (network: Chain | string) => { const variables = { network }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { variables, query: query, diff --git a/web/app.fluidity.money/app/queries/useTokens.ts b/web/app.fluidity.money/app/queries/useTokens.ts index aaf1b6b2b..7b16eb8a7 100644 --- a/web/app.fluidity.money/app/queries/useTokens.ts +++ b/web/app.fluidity.money/app/queries/useTokens.ts @@ -23,9 +23,7 @@ export type Asset = { }; export const useTokens = async () => { - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const { data: { asset }, diff --git a/web/app.fluidity.money/app/queries/useUserRewards.ts b/web/app.fluidity.money/app/queries/useUserRewards.ts index 9f486677d..d494224b1 100644 --- a/web/app.fluidity.money/app/queries/useUserRewards.ts +++ b/web/app.fluidity.money/app/queries/useUserRewards.ts @@ -177,9 +177,7 @@ const useUserRewardsAll = async (network: string) => { const variables = { network, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { variables, query: queryWinnersAll[network as Chain], @@ -199,9 +197,7 @@ const useUserRewardsAll = async (network: string) => { const useUserRewardsByAddress = async (network: string, address: string) => { const variables = { network, address }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { variables, @@ -223,9 +219,7 @@ const useUserPendingRewardsAll = async (network: string) => { const variables = { network, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { variables, query: queryPendingWinnersAll, @@ -247,9 +241,7 @@ const useUserPendingRewardsByAddress = async ( address: string ) => { const variables = { network, address }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { variables, query: queryPendingWinnersByAddress, diff --git a/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts b/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts index 6bb606572..7ce75f5de 100644 --- a/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts +++ b/web/app.fluidity.money/app/queries/useUserUnclaimedRewards.ts @@ -82,9 +82,7 @@ const useUserUnclaimedRewards = async (network: string, address: string) => { }, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return jsonPost( url, diff --git a/web/app.fluidity.money/app/queries/useUserYield.ts b/web/app.fluidity.money/app/queries/useUserYield.ts index 7d500625a..5a6b590ce 100644 --- a/web/app.fluidity.money/app/queries/useUserYield.ts +++ b/web/app.fluidity.money/app/queries/useUserYield.ts @@ -95,9 +95,7 @@ type UserYieldByAddressBody = { const useUserYieldAll = async (network: string) => { const variables = { network }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { variables, query: queryAll, @@ -116,9 +114,7 @@ const useUserYieldAll = async (network: string) => { const useUserYieldByAddress = async (network: string, address: string) => { const variables = { network, address }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; const body = { variables, query: queryByAddress, diff --git a/web/app.fluidity.money/app/queries/useVolumeStats.ts b/web/app.fluidity.money/app/queries/useVolumeStats.ts index 1071ee284..ebe29e72d 100644 --- a/web/app.fluidity.money/app/queries/useVolumeStats.ts +++ b/web/app.fluidity.money/app/queries/useVolumeStats.ts @@ -120,9 +120,7 @@ const useVolumeStatsByAddress = async (network: string, address: string) => { query: queryVolumeByAddress, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return await jsonPost( url, @@ -145,9 +143,7 @@ const useVolumeStats = async (network: string) => { query: queryVolume, }; - const url = process.env.FLU_HASURA_URL; - - if (!url) throw new Error("FLU_HASURA_URL not set!"); + const url = "https://fluidity.hasura.app/v1/graphql"; return await jsonPost( url, From 86fb946f0f08bfeaad3b17917d523254b4a37171 Mon Sep 17 00:00:00 2001 From: user Date: Wed, 10 Jan 2024 15:57:01 +1030 Subject: [PATCH 18/18] Type the stakes array --- .../app/routes/$network/dashboard/airdrop/index.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx index de8f93ecc..ab33e0a5d 100644 --- a/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx +++ b/web/app.fluidity.money/app/routes/$network/dashboard/airdrop/index.tsx @@ -300,7 +300,12 @@ const Airdrop = () => { setCurrentModal(isAirdropModal(destModal) ? destModal : null); }, [location.hash]); - const stakes = []; + const stakes: Array<{ + fluidAmount: BN; + baseAmount: BN; + durationDays: number; + depositDate: Date; + }> = []; const fetchUserTokenBalance = async () => { const userTokenBalance = await Promise.all(