Skip to content

Commit

Permalink
Merge pull request #31 from hoangdv2429/feat/progress_bar
Browse files Browse the repository at this point in the history
Feat/progress bar
  • Loading branch information
kaisbaccour committed Jan 4, 2024
2 parents dae88e4 + 2d0e2de commit eb27509
Show file tree
Hide file tree
Showing 7 changed files with 1,268 additions and 40 deletions.
98 changes: 80 additions & 18 deletions components/chainCards.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useMemo, useCallback } from 'react'
import { useMemo, useCallback, useState, useEffect } from 'react'
import { toast } from 'react-hot-toast';
import { ChainSigningClient } from '../contexts/userClients';
import NextImage from "next/image";
Expand All @@ -8,13 +8,17 @@ import JunoLogo from "../public/JUNO400x400.png";
import AuraLogo from "../public/AURA400x400.jpg";
import OsmosisLogo from "../public/OSMOSIS400x400.png";
import DiceLoader from '../components/diceLoader';
import Progress from './progressBar';
import { ChainType, CheckResponse } from '../pages/api/check';
import { parseTimestamp } from '../services/parsing'
import { randdropClaimMsg } from '../services/contractTx'
import { ethLedgerTxHelper } from '../services/ledgerHelpers';
import { routeNewTab } from '../services/misc';
import { AirdropLiveStatus } from '../pages';
import { signSendAndBroadcastOnInjective } from '../services/injective';
import { calculatePercentage } from '../hooks/cosmwasm';
import { getContractAddress } from '../pages/api/check';
import { Popover, Spin } from 'antd';

const BridgeLinks = {
"injective": "https://tfm.com/bridge?chainTo=nois-1&chainFrom=injective-1&token0=ibc%2FDD9182E8E2B13C89D6B4707C7B43E8DB6193F9FF486AFA0E6CF86B427B0D231A&token1=unois",
Expand Down Expand Up @@ -62,8 +66,8 @@ export const PausedChainCard = ({
return InjectiveLogo;
case "aura":
return AuraLogo;
case "osmosis":
return OsmosisLogo;
case "osmosis":
return OsmosisLogo;
case "stargaze":
return StargazeLogo;
default:
Expand Down Expand Up @@ -133,8 +137,8 @@ export const LiveChainCard = ({
return InjectiveLogo;
case "aura":
return AuraLogo;
case "osmosis":
return OsmosisLogo;
case "osmosis":
return OsmosisLogo;
case "stargaze":
return StargazeLogo;
default:
Expand Down Expand Up @@ -235,7 +239,7 @@ export const LiveChainCard = ({
)}
</div>
{/* Claim Info*/}
<div className="h-[44%] flex justify-center items-center ">
<div className="flex justify-center items-center ">
{!checkResponse || !client ? (
<div className="w-full h-full flex flex-col justify-center items-center gap-y-4 pb-10">
<div className="circle-spinner" />
Expand All @@ -251,6 +255,23 @@ export const LiveChainCard = ({
)
}

const ProgressBar = ({ tokenLeft, claimPercentageLeft }) => (
<div style={{ width: '75%' }}>
<Popover placement="top" content={`${(tokenLeft / Math.pow(10, 6)).toFixed(2)} Nois left`}>
<div>
<Progress percentageLeft={claimPercentageLeft} />
</div>
</Popover>
{
(tokenLeft < 20_000_000 || claimPercentageLeft === 0) && (
<div style={{ color: 'white', display: 'flex', justifyContent: 'center' }}>
All tokens claimed
</div>
)
}
</div>
);

export const ClaimInfo = ({
client,
checkResponse,
Expand All @@ -260,6 +281,34 @@ export const ClaimInfo = ({
checkResponse: CheckResponse;
refetch: () => {}
}) => {
const [claimPercentageLeft, setClaimPercentageLeft] = useState(0)
const [tokenLeft, setTokenLeft] = useState(0)

useEffect(() => {
(async () => {
// If no client, or client is not metamask or ledger, return
if (!client || !client.chain) {
toast.error(`Wallet or Ledger not connected for ${checkResponse.chain}`);
return;
}

const contractAddress = getContractAddress(client.chain)

if (contractAddress === "") {
toast.error(`No randdrop contract available for ${checkResponse.chain}`);
return;
}

const resp = await calculatePercentage(client?.chain, contractAddress)
if (!resp) {
toast.error(`Unable to fetch contract balance for ${checkResponse.chain}`);
return;
}
console.log(resp)
setClaimPercentageLeft(parseFloat(resp.percentageLeft.toFixed(2)))
setTokenLeft(resp.amountLeft)
})()
}, [])

const {
submitted,
Expand Down Expand Up @@ -379,24 +428,37 @@ export const ClaimInfo = ({
}, [client?.walletAddress])

if (!client || checkResponse.userStatus === "not_eligible") {
return <></>
return <ProgressBar tokenLeft={tokenLeft} claimPercentageLeft={claimPercentageLeft} />;
} else {
switch (checkResponse.userStatus) {
case "ready": {
return (
<div className={`w-full h-full p-6 flex justify-center items-start`}>
<button
onClick={() => handleClaimRanddrop()}
className={`py-2 px-6 animate-pulse hover:animate-none hover:shaxdow-neon-md hover:bg-green-500/10 text-green-500 border border-green-500 rounded-xl bg-gradient-to-b from-green-500/10`}
>
{"Roll the dice!"}
</button>
<div style={{ width: '100%'}}>
<div style={{display: 'flex', justifyContent: 'center' }}>
{/* Progress bar */}
<ProgressBar tokenLeft={tokenLeft} claimPercentageLeft={claimPercentageLeft} />
</div>

<div style={{display: 'flex', justifyContent: 'center' }}>
{/* Claim button */}
{
(
<button
onClick={() => handleClaimRanddrop()}
className={`py-2 px-6 animate-pulse hover:animate-none hover:shaxdow-neon-md hover:bg-green-500/10 text-green-500 border border-green-500 rounded-xl bg-gradient-to-b from-green-500/10`}
>
{"Roll the dice!"}
</button>
)
}
</div>
</div>
)
);
}
case "already_won": {
return (
<div className={`w-full h-full p-2 flex flex-col justify-start gap-y-2 items-center`}>
<ProgressBar tokenLeft={tokenLeft} claimPercentageLeft={claimPercentageLeft} />
<div className="text-nois-white/80 text-xs">
{`Submitted at: ${submitted}`}
</div>
Expand Down Expand Up @@ -430,6 +492,7 @@ export const ClaimInfo = ({
case "already_lost": {
return (
<div className={`w-full h-full p-4 flex flex-col justify-start gap-y-2 items-center`}>
<ProgressBar tokenLeft={tokenLeft} claimPercentageLeft={claimPercentageLeft} />
<div className="text-nois-white/80 text-sm">
{`Submitted at: ${submitted}`}
</div>
Expand All @@ -450,9 +513,8 @@ export const ClaimInfo = ({
)
}
default: {
return (
<></>
)
return <ProgressBar tokenLeft={tokenLeft} claimPercentageLeft={claimPercentageLeft} />

}
}
}
Expand Down
11 changes: 11 additions & 0 deletions components/progressBar.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import ProgressBar from 'react-bootstrap/ProgressBar';

const Progress = ({ percentageLeft }) => {
return (
<div style={{marginBottom: '20px'}}>
<ProgressBar striped animated now={percentageLeft} label={`${percentageLeft}%`} style={{color: 'black'}}/>
</div>
);
};

export default Progress;
92 changes: 80 additions & 12 deletions hooks/cosmwasm.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,15 @@
import { useCallback, useState } from "react";
import {
SigningCosmWasmClient,
setupWasmExtension,
} from "@cosmjs/cosmwasm-stargate";
import { setupWasmExtension } from "@cosmjs/cosmwasm-stargate";
import { setupBankExtension } from "@cosmjs/stargate";
import { toBase64, fromBase64, toUtf8, fromUtf8 } from "@cosmjs/encoding";
import { HttpBatchClient, Tendermint34Client, Tendermint37Client } from "@cosmjs/tendermint-rpc";
import { QueryClient } from "@cosmjs/stargate";
import {
getChainConfig,
} from "../services/chainConfig";
import {
ChainType
} from "../pages/api/check";
HttpBatchClient,
Tendermint34Client,
Tendermint37Client,
} from "@cosmjs/tendermint-rpc";
import { QueryClient } from "@cosmjs/stargate";
import { getChainConfig } from "../services/chainConfig";
import { ChainType } from "../pages/api/check";

export const getBatchClient = async (chain: ChainType) => {
const thisChain = getChainConfig(chain);
Expand All @@ -21,7 +19,17 @@ export const getBatchClient = async (chain: ChainType) => {
const tmint = await Tendermint37Client.create(httpBatch);
const queryClient = QueryClient.withExtensions(tmint, setupWasmExtension);
return queryClient;
}
};

const getBankClient = async (chain: ChainType) => {
const thisChain = getChainConfig(chain);
const endpoints = [thisChain.rpc];
const endpoint = endpoints[Math.floor(Math.random() * endpoints.length)];
const httpBatch = new HttpBatchClient(endpoint);
const tmint = await Tendermint37Client.create(httpBatch);
const queryClient = QueryClient.withExtensions(tmint, setupBankExtension);
return queryClient;
};

export function toBinary(obj: any): string {
return toBase64(toUtf8(JSON.stringify(obj)));
Expand All @@ -30,3 +38,63 @@ export function toBinary(obj: any): string {
export function fromBinary(base64: string): any {
return JSON.parse(fromUtf8(fromBase64(base64)));
}

export async function queryContractBalance(
chain: ChainType,
contractAddress: string
): Promise<number> {
// get client with bank extension
const batchClient = await getBankClient(chain);

// Query contract's total NOIS token balances
const balances = await batchClient.bank.allBalances(contractAddress);

// Mapping of known IBC denoms to their chains
const ibcDenoms = {
'stargaze-1': 'ibc/0F181D9F5BB18A8496153C1666E934169515592C135E8E9FCCC355889858EAF9',
'juno-1': 'ibc/1D9E14A1F00613ED39E4B8A8763A20C9BE5B5EA0198F2FE47EAE43CD91A0137B',
'injective-1': 'ibc/DD9182E8E2B13C89D6B4707C7B43E8DB6193F9FF486AFA0E6CF86B427B0D231A',
'aura': 'ibc/1FD48481DAA1B05575FE6D3E35929264437B8424A73243B207BCB67401C7F1FD',
'osmosis': 'ibc/6928AFA9EA721938FED13B051F9DBF1272B16393D20C49EA5E4901BB76D94A90'
};

// Find the NOIS token balance, handling both native and IBC denoms
const noisTokenIdentifier = "unois";
const noisBalance = balances.find((balance) => {
return (
balance.denom === noisTokenIdentifier ||
Object.values(ibcDenoms).includes(balance.denom)
)});

return noisBalance ? parseInt(noisBalance.amount) : 0;
}

export interface ContractQueryResp {
percentageLeft: number,
amountLeft: number
}

export async function calculatePercentage(
chain: ChainType,
contractAddress: string
): Promise<ContractQueryResp> {
// Total amount to be distributed per chain (in unois)
const totalDistribution = {
osmosis: 4_000_000_000_000,
injective: 4_100_000_000_000,
juno: 2_600_000_000_000,
stargaze: 1_200_000_000_000,
aura: 100_000_000_000,
};

const balance = await queryContractBalance(chain, contractAddress);

// Calculate the percentage of NOIS tokens left
const totalForChain = totalDistribution[chain];
const percentageLeft = (balance / totalForChain) * 100;

return {
percentageLeft,
amountLeft: balance
};
}
Loading

0 comments on commit eb27509

Please sign in to comment.