bridge-in flow finished based on new weaver logic
Signed-off-by: Uncle Fatso <uncle.fatso@ghostchain.io>
This commit is contained in:
parent
132bd0986b
commit
42d5f82040
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "ghost-dao-interface",
|
||||
"private": true,
|
||||
"version": "0.7.59-beta-2",
|
||||
"version": "0.8.0",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
@ -31,7 +31,7 @@
|
||||
"@tanstack/react-query-devtools": "^5.67.2",
|
||||
"@wagmi/core": "^2.17.3",
|
||||
"polkadot-api": "^3.3.0",
|
||||
"@polkadot-api/descriptors": "file:./.papi/descriptors",
|
||||
"@polkadot-api/descriptors": "file:.papi/descriptors",
|
||||
"react": "^19.0.0",
|
||||
"react-dom": "^19.0.0",
|
||||
"react-ga4": "^2.1.0",
|
||||
|
||||
@ -447,7 +447,7 @@ const BridgeIn = ({ chainId, address, config, connect }) => {
|
||||
disabled={actionDisabled}
|
||||
onClick={startGhostBridge}
|
||||
>
|
||||
Bond
|
||||
{isPending ? "Pending..." : "Bridge-In"}
|
||||
</PrimaryButton>
|
||||
</Box>
|
||||
</Paper>
|
||||
|
||||
@ -3,6 +3,9 @@ import { useMemo, useState } from "react";
|
||||
import { useTransactionReceipt, useBlockNumber, useTransaction } from 'wagmi';
|
||||
import { decodeEventLog, decodeFunctionData } from 'viem';
|
||||
import { Box, Typography, Link, Skeleton, useTheme } from "@mui/material";
|
||||
import { ss58Encode } from "@polkadot-labs/hdkd-helpers";
|
||||
import { hexToBytes, bytesToHex } from "viem";
|
||||
import { blake2AsU8a } from "@polkadot/util-crypto";
|
||||
|
||||
import CheckIcon from '@mui/icons-material/Check';
|
||||
import SyncIcon from '@mui/icons-material/Sync';
|
||||
@ -18,7 +21,8 @@ import GhostStyledIcon from "../../components/Icon/GhostIcon";
|
||||
import { PrimaryButton } from "../../components/Button";
|
||||
import { abi as GatekeeperAbi } from "../../abi/GhostGatekeeper.json";
|
||||
|
||||
import { useWeaverState } from "../../hooks/staking"
|
||||
import { executePapiBareTransaction } from "../../hooks/helpers";
|
||||
import { useWeaverRoot, useWeaverProof, useWeaverSlotValues, useWeaverMaximumSlots } from "../../hooks/staking"
|
||||
import { useUnstableProvider } from "../../hooks/ghost";
|
||||
import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||
import { shorten, formatNumber, formatCurrency } from "../../helpers";
|
||||
@ -26,6 +30,7 @@ import { shorten, formatNumber, formatCurrency } from "../../helpers";
|
||||
const BridgeInModal = ({ chainId, isOpen, close, config, historyRecord }) => {
|
||||
if (historyRecord === null) return null;
|
||||
|
||||
const [isPending, setIsPending] = useState(false);
|
||||
const [copiedIndex, setCopiedIndex] = useState(null);
|
||||
const { casperApi, client, account } = useUnstableProvider();
|
||||
const { data: blockNumber } = useBlockNumber({ watch: true });
|
||||
@ -35,11 +40,6 @@ const BridgeInModal = ({ chainId, isOpen, close, config, historyRecord }) => {
|
||||
hash: historyRecord.txHash,
|
||||
});
|
||||
|
||||
const functionData = useMemo(() => {
|
||||
if (!txData) return null;
|
||||
return decodeFunctionData({ abi: GatekeeperAbi, data: txData.input })
|
||||
}, [txData]);
|
||||
|
||||
const copyToClipboard = (text, index) => {
|
||||
navigator.clipboard.writeText(text).then(() => {
|
||||
setCopiedIndex(index);
|
||||
@ -55,6 +55,15 @@ const BridgeInModal = ({ chainId, isOpen, close, config, historyRecord }) => {
|
||||
}
|
||||
);
|
||||
|
||||
const functionArgs = useMemo(() => {
|
||||
if (!txData || !chainProperties) return null;
|
||||
const decoded = decodeFunctionData({ abi: GatekeeperAbi, data: txData.input });
|
||||
const prefix = chainProperties.properties.ss58Format;
|
||||
const receiverRaw = decoded?.args.at(0);
|
||||
const receiver = receiverRaw ? ss58Encode(receiverRaw, prefix) : null;
|
||||
return { receiver, amount: decoded?.args.at(1) };
|
||||
}, [txData, chainProperties]);
|
||||
|
||||
const { data: networkData } = useSWR(
|
||||
casperApi ? ['networkData', casperApi, chainId] : null,
|
||||
async () => {
|
||||
@ -67,6 +76,19 @@ const BridgeInModal = ({ chainId, isOpen, close, config, historyRecord }) => {
|
||||
}
|
||||
);
|
||||
|
||||
const { data: loomState } = useSWR(
|
||||
casperApi ? ['loomState', casperApi, chainId] : null,
|
||||
async () => {
|
||||
const key = BigInt(chainId);
|
||||
const res = await casperApi.query.GhostWeaver.LoomStates.getValue(key, 0n);
|
||||
return res;
|
||||
},
|
||||
{
|
||||
refreshInterval: 12000,
|
||||
revalidateOnFocus: true
|
||||
}
|
||||
);
|
||||
|
||||
const chainInfo = useMemo(() => {
|
||||
const client = config?.getClient();
|
||||
return {
|
||||
@ -108,33 +130,36 @@ const BridgeInModal = ({ chainId, isOpen, close, config, historyRecord }) => {
|
||||
return allDecodedLogs.find(l => l.eventName === 'ThreadInserted');
|
||||
}, [allDecodedLogs]);
|
||||
|
||||
// TODO: revisit, we need other block to be used here
|
||||
// TODO: how to verify the fact that merkle root is correct???
|
||||
// const xxxx = useWeaverState(chainId, receipt.blockNumber, bridgeInInfo?.args);
|
||||
const { maximumSlots } = useWeaverMaximumSlots(chainId);
|
||||
const { merkleRoot: evmMerkleRoot } = useWeaverRoot(chainId, loomState?.at_block, bridgeInInfo?.args);
|
||||
const { merkleProof } = useWeaverProof(chainId, loomState?.at_block, bridgeInInfo?.args);
|
||||
const { slotValues } = useWeaverSlotValues(chainId, loomState?.at_block, bridgeInInfo?.args);
|
||||
|
||||
// TODO: functionData could be here
|
||||
const localString = new Date(historyRecord.submitted).toLocaleString();
|
||||
const receiver = "sfKCC7CEfJLTgGopghSPB5EtNfLVUu34nMtiW3Taf1GuwVz3Z";
|
||||
|
||||
const rawAmount = 1000000000000000000n;
|
||||
const bridgedAmount = new DecimalBigNumber(
|
||||
rawAmount,
|
||||
chainProperties?.properties.tokenDecimals ?? 18
|
||||
);
|
||||
const bridgedAmount = useMemo(() => {
|
||||
if (!functionArgs) return null;
|
||||
return new DecimalBigNumber(
|
||||
functionArgs.amount,
|
||||
chainProperties?.properties.tokenDecimals ?? 18
|
||||
)
|
||||
}, [functionArgs, chainProperties]);
|
||||
|
||||
const estimatedFee = useMemo(() => {
|
||||
if (!networkData) return null
|
||||
if (!networkData) return null;
|
||||
return networkData.incoming_share / 10000000;
|
||||
}, [networkData]);
|
||||
|
||||
const estimatedReceived = useMemo(() => {
|
||||
if (!functionArgs) return null;
|
||||
|
||||
const hundredPercent = 1000000000;
|
||||
const incomingShare = networkData ? networkData.incoming_share : 0;
|
||||
const result = hundredPercent - incomingShare;
|
||||
|
||||
const value = Number(rawAmount) * result / hundredPercent;
|
||||
const value = Number(functionArgs.amount) * result / hundredPercent;
|
||||
return new DecimalBigNumber(value, chainProperties?.properties.tokenDecimals ?? 18)
|
||||
}, [networkData, chainProperties]);
|
||||
}, [functionArgs, networkData, chainProperties]);
|
||||
|
||||
const finalization = useMemo(() => {
|
||||
if (!receipt || !blockNumber || !networkData) return null;
|
||||
@ -142,32 +167,124 @@ const BridgeInModal = ({ chainId, isOpen, close, config, historyRecord }) => {
|
||||
return Math.max(0, Number(finalityDelay + receipt.blockNumber - blockNumber));
|
||||
}, [receipt, blockNumber, networkData]);
|
||||
|
||||
// TODO: networkId, session,
|
||||
// TODO: EvmThreadProof: slotIndex global % SLOTS, proofIndex % SLOTS, receiver sf, amount raw
|
||||
const rootIncluded = useMemo(() => {
|
||||
if (!loomState || !receipt) return false;
|
||||
return evmMerkleRoot === loomState.root_hash && receipt.blockNumber < loomState.at_block;
|
||||
}, [loomState, receipt, evmMerkleRoot]);
|
||||
|
||||
// TODO: compute locally the arguments
|
||||
// https://git.ghostchain.io/ghostchain/ghost-node/src/commit/cc7721e3899f9740e35f65f3feb4cdc621926166/pallets/weaver/src/types.rs#L400
|
||||
const weaverArgs = useMemo(() => {
|
||||
if (!bridgeInInfo) return null;
|
||||
return {
|
||||
sessionIndex: bridgeInInfo.args.session,
|
||||
slotIndex: bridgeInInfo.args.index % maximumSlots,
|
||||
valueIndex: bridgeInInfo.args.index / maximumSlots,
|
||||
};
|
||||
}, [maximumSlots, bridgeInInfo]);
|
||||
|
||||
const pulledThreadKey = useMemo(() => {
|
||||
if (!chainId || !weaverArgs) return "0x0000000000000000000000000000000000000000000000000000000000000000";
|
||||
|
||||
const padU64 = (val) => "0x" + BigInt(val).toString(16).padStart(64, "0");
|
||||
|
||||
const metadata = [
|
||||
padU64(weaverArgs.sessionIndex),
|
||||
padU64(weaverArgs.valueIndex),
|
||||
padU64(weaverArgs.slotIndex),
|
||||
padU64(chainId)
|
||||
].map(hexToBytes);
|
||||
|
||||
let currentHash = metadata[0];
|
||||
|
||||
for (let i = 1; i < metadata.length; i++) {
|
||||
const combined = new Uint8Array(64);
|
||||
combined.set(currentHash, 0);
|
||||
combined.set(metadata[i], 32);
|
||||
currentHash = blake2AsU8a(combined);
|
||||
}
|
||||
|
||||
return bytesToHex(currentHash);
|
||||
}, [chainId, weaverArgs]);
|
||||
|
||||
const { data: threadPulled, mutate: threadPulledMutate } = useSWR(
|
||||
casperApi ? ['threadPulled', casperApi, pulledThreadKey, chainId] : null,
|
||||
async () => {
|
||||
const key = BigInt(chainId);
|
||||
const res = await casperApi.query.GhostWeaver.PulledThreads.getValue(pulledThreadKey);
|
||||
return res;
|
||||
},
|
||||
{
|
||||
revalidateOnFocus: true
|
||||
}
|
||||
);
|
||||
|
||||
const pullCurrentThread = async () => {
|
||||
setIsPending(true);
|
||||
|
||||
try {
|
||||
const txArgs = {
|
||||
network_id: BigInt(chainId),
|
||||
session: weaverArgs.sessionIndex,
|
||||
thread_proof: {
|
||||
type: "EvmThreadProof",
|
||||
value: {
|
||||
slot_index: weaverArgs.valueIndex,
|
||||
proof_index: weaverArgs.slotIndex,
|
||||
receiver: functionArgs.receiver,
|
||||
amount: functionArgs.amount,
|
||||
proof: merkleProof,
|
||||
slots: slotValues,
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const tx = casperApi.tx.GhostWeaver.pull_thread(txArgs);
|
||||
const bareTx = await tx.getBareTx();
|
||||
|
||||
await executePapiBareTransaction({ client, bareTx });
|
||||
await threadPulledMutate();
|
||||
} finally {
|
||||
setIsPending(false);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Modal
|
||||
maxWidth="420px"
|
||||
minHeight="200px"
|
||||
open={isOpen}
|
||||
headerText={
|
||||
<>
|
||||
{bridgeInInfo && "Bridge-In"}
|
||||
{!bridgeInInfo && "Parsing Transaction Hash"}
|
||||
</>
|
||||
headerContent={
|
||||
<Box display="flex" flexDirection="row">
|
||||
{bridgeInInfo
|
||||
? <Box display="flex" gap="10px">
|
||||
<Typography variant="h5">Bridge-In</Typography>
|
||||
<Link
|
||||
underline="always"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
href={`${chainInfo.url}/tx/${historyRecord.txHash}`}
|
||||
>
|
||||
<Typography variant="h5">
|
||||
{bridgeInInfo ? shorten(historyRecord.txHash, 7, -5) : ""}
|
||||
</Typography>
|
||||
</Link>
|
||||
</Box>
|
||||
: <Typography variant="h5">Parsing Transaction Hash</Typography>
|
||||
}
|
||||
</Box>
|
||||
}
|
||||
onClose={() => close()}
|
||||
onClose={() => isPending ? {} : close()}
|
||||
>
|
||||
<Box display="flex" flexDirection="column">
|
||||
<Box width="100%" gap="5px" display="flex" flexDirection="column" justifyContent="space-between" alignItems="center">
|
||||
<BridgeInProgress
|
||||
submissionBlock={receipt ? receipt.blockNumber : 0}
|
||||
blockNumber={blockNumber}
|
||||
chainId={chainId}
|
||||
casperApi={casperApi}
|
||||
finalization={finalization}
|
||||
loomState={loomState}
|
||||
rootIncluded={rootIncluded}
|
||||
claimed={threadPulled === null}
|
||||
/>
|
||||
|
||||
<Box
|
||||
@ -191,15 +308,15 @@ const BridgeInModal = ({ chainId, isOpen, close, config, historyRecord }) => {
|
||||
/>
|
||||
|
||||
<DataRow
|
||||
title="Receiver [-]"
|
||||
title="Receiver"
|
||||
tooltip="some description to be added."
|
||||
balance={
|
||||
<Link
|
||||
style={{ display: "flex", flexDirection: "row", justifyContent: "center", alignItems: "center" }}
|
||||
onClick={() => copyToClipboard(receiver, 0)}
|
||||
onClick={() => functionArgs?.receiver ? copyToClipboard(functionArgs.receiver, 0) : {}}
|
||||
>
|
||||
<Typography variant="body1">
|
||||
{bridgeInInfo ? shorten(receiver, 11, -8) : <Skeleton width="120px" />}
|
||||
{functionArgs?.receiver ? shorten(functionArgs.receiver, 11, -8) : <Skeleton width="120px" />}
|
||||
</Typography>
|
||||
<GhostStyledIcon
|
||||
sx={{ marginLeft: "5px", width: "12px", height: "12px" }}
|
||||
@ -218,19 +335,6 @@ const BridgeInModal = ({ chainId, isOpen, close, config, historyRecord }) => {
|
||||
: <Skeleton width="120px" />
|
||||
}
|
||||
/>
|
||||
|
||||
<DataRow
|
||||
title="Transaction Hash [+]"
|
||||
tooltip="some description to be added."
|
||||
balance={historyRecord
|
||||
? <Link href={`${chainInfo.url}/tx/${historyRecord.txHash}`} target="_blank" rel="noopener noreferrer">
|
||||
<Typography variant="body1">
|
||||
{bridgeInInfo ? shorten(historyRecord.txHash, 11, -8) : <Skeleton width="120px" />}
|
||||
</Typography>
|
||||
</Link>
|
||||
: <Skeleton width="120px" />
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<hr style={{ width: "100%" }} />
|
||||
@ -250,9 +354,14 @@ const BridgeInModal = ({ chainId, isOpen, close, config, historyRecord }) => {
|
||||
}}
|
||||
>
|
||||
<DataRow
|
||||
title="Gross Bridged [-]"
|
||||
title="Gross Bridged"
|
||||
tooltip="some description to be added."
|
||||
balance={<Typography variant="body1">{formatCurrency(bridgedAmount, 5, chainProperties?.properties.tokenSymbol ?? "")}</Typography>}
|
||||
balance={bridgedAmount
|
||||
? <Typography variant="body1">
|
||||
{formatCurrency(bridgedAmount.toString(), 5, chainProperties?.properties.tokenSymbol ?? "")}
|
||||
</Typography>
|
||||
: <Skeleton width="120px" />
|
||||
}
|
||||
/>
|
||||
|
||||
<DataRow
|
||||
@ -264,18 +373,32 @@ const BridgeInModal = ({ chainId, isOpen, close, config, historyRecord }) => {
|
||||
<DataRow
|
||||
title="Net Received"
|
||||
tooltip="some description to be added."
|
||||
balance={<Typography variant="body1">{formatCurrency(estimatedReceived.toString(), 5, chainProperties?.properties.tokenSymbol ?? "")}</Typography>}
|
||||
balance={estimatedReceived
|
||||
? <Typography variant="body1">
|
||||
{formatCurrency(estimatedReceived.toString(), 5, chainProperties?.properties.tokenSymbol ?? "")}
|
||||
</Typography>
|
||||
: <Skeleton width="120px" />
|
||||
}
|
||||
/>
|
||||
</Box>
|
||||
|
||||
<PrimaryButton fullWidth>Claim Bridge-In</PrimaryButton>
|
||||
<PrimaryButton
|
||||
fullWidth
|
||||
disabled={!rootIncluded || isPending || threadPulled === null}
|
||||
onClick={pullCurrentThread}
|
||||
>
|
||||
{isPending
|
||||
? "Pending..."
|
||||
: threadPulled === null ? "Transaction Claimed" : "Claim Bridge-In"
|
||||
}
|
||||
</PrimaryButton>
|
||||
</Box>
|
||||
</Box>
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
|
||||
const BridgeInProgress = ({ chainId, casperApi, finalization, blockNumber }) => {
|
||||
const BridgeInProgress = ({ chainId, submissionBlock, claimed, casperApi, finalization, loomState, rootIncluded }) => {
|
||||
const theme = useTheme();
|
||||
|
||||
const { data: weaverAuthorities } = useSWR(
|
||||
@ -286,6 +409,19 @@ const BridgeInProgress = ({ chainId, casperApi, finalization, blockNumber }) =>
|
||||
}
|
||||
);
|
||||
|
||||
const { data: networkAttestations } = useSWR(
|
||||
casperApi ? ['networkAttestations', casperApi] : null,
|
||||
async () => {
|
||||
const key = BigInt(chainId);
|
||||
const res = await casperApi.query.GhostWeaver.NetworkAttestations.getValue(key);
|
||||
return res;
|
||||
},
|
||||
{
|
||||
refreshInterval: 12000,
|
||||
revalidateOnFocus: true
|
||||
}
|
||||
);
|
||||
|
||||
const { data: tapestryDraft } = useSWR(
|
||||
casperApi ? ['tapestryDraft', casperApi, chainId] : null,
|
||||
async () => {
|
||||
@ -312,45 +448,29 @@ const BridgeInProgress = ({ chainId, casperApi, finalization, blockNumber }) =>
|
||||
}
|
||||
);
|
||||
|
||||
const { data: loomState } = useSWR(
|
||||
casperApi ? ['loomState', casperApi, chainId] : null,
|
||||
async () => {
|
||||
const key = BigInt(chainId);
|
||||
const res = await casperApi.query.GhostWeaver.LoomStates.getValue(key, 0n);
|
||||
return res;
|
||||
},
|
||||
{
|
||||
refreshInterval: 12000,
|
||||
revalidateOnFocus: true
|
||||
}
|
||||
);
|
||||
|
||||
const rootIncluded = useMemo(() => {
|
||||
if (!loomState || !blockNumber) return false;
|
||||
if (blockNumber >= loomState.at_block) return true;
|
||||
return false;
|
||||
});
|
||||
|
||||
return (
|
||||
<Box p="10px 0" width="100%" display="flex" justifyContent="space-between" alignItems="center">
|
||||
{finalization === null || finalization > 0
|
||||
? <BlockFinalization theme={theme} finalization={finalization} />
|
||||
: <SyncTarget
|
||||
theme={theme}
|
||||
weaverAuthorities={weaverAuthorities}
|
||||
networkAttestations={networkAttestations}
|
||||
rootIncluded={rootIncluded}
|
||||
blockNumber={blockNumber}
|
||||
submissionBlock={submissionBlock}
|
||||
loomState={loomState}
|
||||
tapestryDraft={tapestryDraft}
|
||||
/>
|
||||
}
|
||||
<RootVerification
|
||||
theme={theme}
|
||||
finalization={finalization}
|
||||
rootIncluded={rootIncluded}
|
||||
tapestryDraft={tapestryDraft}
|
||||
tapestryStrand={tapestryStrand}
|
||||
totalAuthorities={weaverAuthorities?.length ?? 0}
|
||||
/>
|
||||
<ProofSubmission theme={theme} rootIncluded={rootIncluded} />
|
||||
<ProofSubmission claimed={claimed} theme={theme} rootIncluded={rootIncluded} />
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
@ -374,7 +494,7 @@ const ProofSubmission = ({ theme, claimed, rootIncluded }) => {
|
||||
width: "35px",
|
||||
height: "35px",
|
||||
transformOrigin: "center",
|
||||
animation: rootIncluded && 'waitingForClaim 4s ease-in-out infinite',
|
||||
animation: (rootIncluded && !claimed) && 'waitingForClaim 4s ease-in-out infinite',
|
||||
'@keyframes waitingForClaim': {
|
||||
'0%, 100%': { opacity: 0.4 },
|
||||
'50%': { opacity: 1 },
|
||||
@ -387,21 +507,22 @@ const ProofSubmission = ({ theme, claimed, rootIncluded }) => {
|
||||
<Typography variant="caption">
|
||||
{rootIncluded
|
||||
? claimed ? "Success" : "Claim Ready"
|
||||
: "Pending..."
|
||||
: "Claim Pending..."
|
||||
}
|
||||
</Typography>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
|
||||
const RootVerification = ({ theme, tapestryDraft, rootIncluded, totalAuthorities, tapestryStrand }) => {
|
||||
const RootVerification = ({ theme, finalization, tapestryDraft, rootIncluded, totalAuthorities, tapestryStrand }) => {
|
||||
const finalizationPending = useMemo(() => finalization > 0, [finalization]);
|
||||
|
||||
const rootVerificationText = useMemo(() => {
|
||||
if (rootIncluded) return "Synced";
|
||||
if (!tapestryStrand) return "Pending...";
|
||||
if (!tapestryDraft || finalizationPending) return "Pending...";
|
||||
|
||||
let maxOnesCount = 0;
|
||||
|
||||
tapestryStrand.forEach(item => {
|
||||
tapestryStrand?.forEach(item => {
|
||||
const dataArray = item[1]?.data || [];
|
||||
const totalOnes = dataArray.reduce((sum, num) => {
|
||||
const onesInNumber = num.toString(2).split('1').length - 1;
|
||||
@ -414,14 +535,14 @@ const RootVerification = ({ theme, tapestryDraft, rootIncluded, totalAuthorities
|
||||
});
|
||||
|
||||
return `${maxOnesCount} / ${totalAuthorities}`;
|
||||
}, [rootIncluded, tapestryStrand, totalAuthorities]);
|
||||
}, [rootIncluded, tapestryDraft, tapestryStrand, totalAuthorities, finalizationPending]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
sx={{
|
||||
transition: "all 0.8s ease",
|
||||
transform: !rootIncluded && tapestryDraft && "scale(1.2)",
|
||||
color: (rootIncluded || tapestryDraft) && theme.colors.primary[300]
|
||||
transform: !rootIncluded && !finalizationPending && tapestryDraft && "scale(1.2)",
|
||||
color: (rootIncluded || tapestryDraft) && !finalizationPending && theme.colors.primary[300]
|
||||
}}
|
||||
maxWidth="120px"
|
||||
display="flex"
|
||||
@ -449,14 +570,22 @@ const RootVerification = ({ theme, tapestryDraft, rootIncluded, totalAuthorities
|
||||
)
|
||||
}
|
||||
|
||||
const SyncTarget = ({ tapestryDraft, loomState, rootIncluded, blockNumber, theme }) => {
|
||||
const SyncTarget = ({ weaverAuthorities, networkAttestations, tapestryDraft, submissionBlock, loomState, rootIncluded, theme }) => {
|
||||
const syncTargetText = useMemo(() => {
|
||||
if (rootIncluded) return "Synced";
|
||||
if (!tapestryDraft || !loomState) return "Pending...";
|
||||
if (blockNumber >= loomState.at_block) return "Synced"
|
||||
|
||||
return `${formatNumber(Number(blockNumber - loomState.at_block))} block behind`;
|
||||
}, [rootIncluded, tapestryDraft, loomState, blockNumber]);
|
||||
if (!tapestryDraft || !loomState) {
|
||||
const total = weaverAuthorities ? weaverAuthorities.length : 0;
|
||||
const count = networkAttestations
|
||||
? networkAttestations.filter(v => v !== undefined).length
|
||||
: 0;
|
||||
return `${count} / ${total}`
|
||||
}
|
||||
|
||||
if (submissionBlock < loomState.at_block) return "Synced";
|
||||
|
||||
return `${formatNumber(Number(submissionBlock - loomState.at_block))} block behind`;
|
||||
}, [rootIncluded, tapestryDraft, loomState, weaverAuthorities, submissionBlock, networkAttestations]);
|
||||
|
||||
return (
|
||||
<Box
|
||||
|
||||
@ -18,6 +18,7 @@ import {
|
||||
|
||||
import { useLocation } from "react-router-dom";
|
||||
import { useEffect, useState, useMemo, useCallback } from "react";
|
||||
import useSWR from 'swr';
|
||||
import ReactGA from "react-ga4";
|
||||
import SettingsIcon from '@mui/icons-material/Settings';
|
||||
|
||||
@ -33,7 +34,9 @@ import { Tab, Tabs } from "../../components/Tabs/Tabs";
|
||||
|
||||
import { useTokenSymbol } from "../../hooks/tokens";
|
||||
import { useLocalStorage } from "../../hooks/localstorage";
|
||||
import { useUnstableProvider } from "../../hooks/ghost";
|
||||
import { shorten } from "../../helpers";
|
||||
import { networkAvgBlockSpeed } from "../../constants";
|
||||
|
||||
import EraseModal from "./EraseModal";
|
||||
import SettingsModal from "./SettingsModal";
|
||||
@ -41,7 +44,7 @@ import DexViewModal from "./DexViewModal";
|
||||
import StakingViewModal from "./StakingViewModal";
|
||||
import BridgeInModal from "./BridgeInModal";
|
||||
|
||||
const HistoryItem = ({ item, chainId, config, currentTime, eraseRecord, setViewModalOpen, isSmallScreen }) => {
|
||||
const HistoryItem = ({ item, chainId, config, currentTime, eraseRecord, setViewModalOpen, isSmallScreen, finalityDelay }) => {
|
||||
const theme = useTheme();
|
||||
const isVerySmallScreen = useMediaQuery("(max-width: 450px)");
|
||||
|
||||
@ -57,19 +60,15 @@ const HistoryItem = ({ item, chainId, config, currentTime, eraseRecord, setViewM
|
||||
}, [config]);
|
||||
|
||||
const chipStatus = useMemo(() => {
|
||||
const delay = 3600000; // useEvmNetwork({ evmChainId: chainId })
|
||||
const width = isVerySmallScreen ? "21px" : "100px"
|
||||
const delay = Number(finalityDelay * networkAvgBlockSpeed(chainId)) * 1000;
|
||||
const width = isVerySmallScreen ? "21px" : "100px";
|
||||
|
||||
if (item.submitted + delay > currentTime) {
|
||||
return <Chip sx={{ width: width }} label={isVerySmallScreen ? "" : "Pending"} template={"gray"} />
|
||||
}
|
||||
|
||||
// darkGray for final
|
||||
|
||||
return <Chip sx={{ width: width }} label={isVerySmallScreen ? "" : "Executed"} template={"success"} />
|
||||
}, [item, currentTime, isVerySmallScreen])
|
||||
|
||||
// TODO: put correct values into TokenStack based on type
|
||||
return <Chip sx={{ width: width }} label={isVerySmallScreen ? "" : "Ready"} template={"success"} />
|
||||
}, [item, currentTime, isVerySmallScreen, finalityDelay])
|
||||
|
||||
if (isSmallScreen || isVerySmallScreen) {
|
||||
return (
|
||||
@ -153,13 +152,30 @@ const HistoryList = ({ chainId, storedTransactions, historyType, config, eraseRe
|
||||
const [viewModalOpen, setViewModalOpen] = useState(null);
|
||||
|
||||
const { CONSTANTS } = useLocalStorage();
|
||||
const { casperApi } = useUnstableProvider();
|
||||
|
||||
const { data: networkData, error, isLoading } = useSWR(
|
||||
casperApi ? ['networkData', casperApi, chainId] : null,
|
||||
async () => {
|
||||
const key = BigInt(chainId);
|
||||
const res = await casperApi.query.GhostNetworks.Networks.getValue(key);
|
||||
return res;
|
||||
},
|
||||
{
|
||||
revalidateOnFocus: true
|
||||
}
|
||||
);
|
||||
|
||||
const finalityDelay = useMemo(() => {
|
||||
return networkData ? networkData.finality_delay : 420n;
|
||||
}, [networkData]);
|
||||
|
||||
useEffect(() => {
|
||||
const intervalId = setInterval(() => {
|
||||
setCurrentTime(Date.now());
|
||||
}, 5000);
|
||||
}, 1000);
|
||||
return () => clearInterval(intervalId);
|
||||
}, [])
|
||||
}, []);
|
||||
|
||||
const historyContainer = useMemo(() => {
|
||||
if (isSmallScreen) {
|
||||
@ -173,6 +189,7 @@ const HistoryList = ({ chainId, storedTransactions, historyType, config, eraseRe
|
||||
config={config}
|
||||
chainId={chainId}
|
||||
currentTime={currentTime}
|
||||
finalityDelay={finalityDelay}
|
||||
eraseRecord={() => eraseRecord(i)}
|
||||
setViewModalOpen={() => setViewModalOpen(i)}
|
||||
isSmallScreen={isSmallScreen}
|
||||
@ -201,6 +218,7 @@ const HistoryList = ({ chainId, storedTransactions, historyType, config, eraseRe
|
||||
item={item}
|
||||
config={config}
|
||||
currentTime={currentTime}
|
||||
finalityDelay={finalityDelay}
|
||||
eraseRecord={() => eraseRecord(i)}
|
||||
setViewModalOpen={() => setViewModalOpen(i)}
|
||||
isSmallScreen={isSmallScreen}
|
||||
|
||||
@ -11,44 +11,7 @@ import { startFromWorker } from "polkadot-api/smoldot/from-worker"
|
||||
import SmWorker from "polkadot-api/smoldot/worker?worker"
|
||||
|
||||
import { casper as casperMetadata } from "@polkadot-api/descriptors";
|
||||
|
||||
// TODO: move me to file
|
||||
const chainSpec = `{
|
||||
"badBlocks": null,
|
||||
"bootNodes": [
|
||||
"/dns/bootnode007.ghostchain.io/tcp/30335/p2p/12D3KooWF9SWxz9dmy6vfndQhoxqCa7PESaoFWEiF8Jkqh4xKDRf",
|
||||
"/dns/bootnode007.ghostchain.io/tcp/30336/ws/p2p/12D3KooWF9SWxz9dmy6vfndQhoxqCa7PESaoFWEiF8Jkqh4xKDRf",
|
||||
"/dns/bootnode007.ghostchain.io/tcp/443/wss/p2p/12D3KooWF9SWxz9dmy6vfndQhoxqCa7PESaoFWEiF8Jkqh4xKDRf",
|
||||
"/dns/bootnode70.chain.ghostchain.io/tcp/30334/p2p/12D3KooWP3h5dSdqcpvsCr7fp1jyfqDj291QDZ68a4gY6VQ8T1nW",
|
||||
"/dns/bootnode70.chain.ghostchain.io/tcp/30335/ws/p2p/12D3KooWP3h5dSdqcpvsCr7fp1jyfqDj291QDZ68a4gY6VQ8T1nW",
|
||||
"/dns/bootnode70.chain.ghostchain.io/tcp/30336/wss/p2p/12D3KooWP3h5dSdqcpvsCr7fp1jyfqDj291QDZ68a4gY6VQ8T1nW"
|
||||
],
|
||||
"chainType": "Live",
|
||||
"forkBlocks": null,
|
||||
"genesis": {
|
||||
"stateRootHash": "0xb4784a3c8f2f29ba3f191d563f1166f08f4e0337e114679c0f24ef77d06e10e4"
|
||||
},
|
||||
"id": "casper_staging_testnet",
|
||||
"lightSyncState": {
|
||||
"babeEpochChanges": "0x042c315b655c7144df4bfdc41837eeacb84d80aee06eaba51f6941a0c7a26cb1bf5d090000015e9de408000000000ea2e40800000000049b2e88b8ce43a677c1ca90f62134800b7e510c0c353dad719cad82faf6136cfb0d0e0000010ea2e40800000000bea6e408000000000000082c315b655c7144df4bfdc41837eeacb84d80aee06eaba51f6941a0c7a26cb1bf5d0900000103000000000000005e9de40800000000b00400000000000014daaaaab6a6e574099e24ae9bb75b543610edef9d374fa85a378edb573b47615f010000000000000074fa7381a7a74b316afb6793a00387eed9d95d46a69866cbb316b5d9c918af0e0100000000000000e0f0a776ecc9fa5e1f22e2fa001fe3fba5aea52b9444bc894b45589d4213247501000000000000006c4dd88b43e2011cf9a6a73d53446336ac9e04cdd4ca23587df63187ac455e4901000000000000003c944c704cae203619b9e7a5a4b6742736da6a8e76c762291bebdc7652cfec2f01000000000000002ff7c765405e9c11a59525a08173bb1fa59e5e281090f8e4d1824469f513d0cc01000000000000000400000000000000029b2e88b8ce43a677c1ca90f62134800b7e510c0c353dad719cad82faf6136cfb0d0e00000104000000000000000ea2e40800000000b00400000000000014daaaaab6a6e574099e24ae9bb75b543610edef9d374fa85a378edb573b47615f010000000000000074fa7381a7a74b316afb6793a00387eed9d95d46a69866cbb316b5d9c918af0e0100000000000000e0f0a776ecc9fa5e1f22e2fa001fe3fba5aea52b9444bc894b45589d4213247501000000000000006c4dd88b43e2011cf9a6a73d53446336ac9e04cdd4ca23587df63187ac455e4901000000000000003c944c704cae203619b9e7a5a4b6742736da6a8e76c762291bebdc7652cfec2f0100000000000000dea465ff8bf16938cc9ead89bf9fdb5d9c495fad61fd952b2067ebdc51c4e1c10100000000000000040000000000000002",
|
||||
"babeFinalizedBlockWeight": 1039,
|
||||
"finalizedBlockHeader": "0x6ed6c2debc2e5fd4e7db0d14426d1b904e6c101f2c62a71b8e891c217ba79079f9433280c0257a860f793833bd6bed6b9f86094400aa8e5ea24a81752f0f046ff5ed560f7231760c622ae35d3968fbab033ed34d950b57a7937ae45c411d1d384748080642414245b50103000000004fa0e40800000000a2c7d71b4e1f94c0208c9730ab93955b08c8d7ac86d2fc6ec5f62cc3272a5f1ec0e28c798461372109ee3e12f03ff66ea5ad9cac5b1c37d7280d2333d0226f0865ea77a801bad79785a8ca83c87f0dbf1e36936a6f65cd7b125a41c52f38f80105424142450101caaa6fe5f9df57930e2ac08aef43b75d5477d410c73c3a8e6dea9d5503b9fd25eae1d12b6604194389e22f3f4265d581eb162d1dc5a9034247fe33765dddbe8c",
|
||||
"grandpaAuthoritySet": "0x1455446f9a7aa99ced06b317c80ce90d56b84e56526775683af2525969e8da0b640100000000000000236d2fa03f4ed8cb65de7e514d7540159b328f1c170dd402b094ad7fbf5472180100000000000000b63c5a0cf342b9b04931bc8ed74d7d0165ab99ab5f8a4514797d4b299a4501fe01000000000000008f9ea20bf4a807a8e710f7559dece86e94672b5b361de157bdaa5c1f37849f8d01000000000000000aa3a88f6b777c95c3dfe7e997b76798413f16aa325f34824cae0c9102b281d5010000000000000000000000000000000001fe1000000000"
|
||||
},
|
||||
"name": "Casper Staging Testnet",
|
||||
"properties": {
|
||||
"ss58Format": 1996,
|
||||
"tokenDecimals": 18,
|
||||
"tokenSymbol": "CSPR"
|
||||
},
|
||||
"protocolId": "cspr",
|
||||
"telemetryEndpoints": [
|
||||
[
|
||||
"/dns/telemetry.ghostchain.io/tcp/443/x-parity-wss/%2Fsubmit%2F",
|
||||
0
|
||||
]
|
||||
]
|
||||
}`;
|
||||
import { casperChainSpec } from "./chainSpecs";
|
||||
|
||||
const GHOST_CONNECT_EXTENSION = "GHOST Connect Browser Extension"
|
||||
const MAX_BLOCK_TIMEOUT = 15000
|
||||
@ -71,7 +34,7 @@ export const UnstableProviderProvider = ({ children }) => {
|
||||
try {
|
||||
const smoldot = startFromWorker(new SmWorker());
|
||||
provider = createClientOther(
|
||||
getSmProvider(() => smoldot.addChain({ chainSpec })),
|
||||
getSmProvider(() => smoldot.addChain({ chainSpec: casperChainSpec })),
|
||||
)
|
||||
|
||||
if (isMounted) {
|
||||
|
||||
36
src/hooks/ghost/chainSpecs.js
Normal file
36
src/hooks/ghost/chainSpecs.js
Normal file
@ -0,0 +1,36 @@
|
||||
export const casperChainSpec = `{
|
||||
"badBlocks": null,
|
||||
"bootNodes": [
|
||||
"/dns/bootnode007.ghostchain.io/tcp/30335/p2p/12D3KooWF9SWxz9dmy6vfndQhoxqCa7PESaoFWEiF8Jkqh4xKDRf",
|
||||
"/dns/bootnode007.ghostchain.io/tcp/30336/ws/p2p/12D3KooWF9SWxz9dmy6vfndQhoxqCa7PESaoFWEiF8Jkqh4xKDRf",
|
||||
"/dns/bootnode007.ghostchain.io/tcp/443/wss/p2p/12D3KooWF9SWxz9dmy6vfndQhoxqCa7PESaoFWEiF8Jkqh4xKDRf",
|
||||
"/dns/bootnode70.chain.ghostchain.io/tcp/30334/p2p/12D3KooWP3h5dSdqcpvsCr7fp1jyfqDj291QDZ68a4gY6VQ8T1nW",
|
||||
"/dns/bootnode70.chain.ghostchain.io/tcp/30335/ws/p2p/12D3KooWP3h5dSdqcpvsCr7fp1jyfqDj291QDZ68a4gY6VQ8T1nW",
|
||||
"/dns/bootnode70.chain.ghostchain.io/tcp/30336/wss/p2p/12D3KooWP3h5dSdqcpvsCr7fp1jyfqDj291QDZ68a4gY6VQ8T1nW"
|
||||
],
|
||||
"chainType": "Live",
|
||||
"forkBlocks": null,
|
||||
"genesis": {
|
||||
"stateRootHash": "0xb4784a3c8f2f29ba3f191d563f1166f08f4e0337e114679c0f24ef77d06e10e4"
|
||||
},
|
||||
"id": "casper_staging_testnet",
|
||||
"lightSyncState": {
|
||||
"babeEpochChanges": "0x042c315b655c7144df4bfdc41837eeacb84d80aee06eaba51f6941a0c7a26cb1bf5d090000015e9de408000000000ea2e40800000000049b2e88b8ce43a677c1ca90f62134800b7e510c0c353dad719cad82faf6136cfb0d0e0000010ea2e40800000000bea6e408000000000000082c315b655c7144df4bfdc41837eeacb84d80aee06eaba51f6941a0c7a26cb1bf5d0900000103000000000000005e9de40800000000b00400000000000014daaaaab6a6e574099e24ae9bb75b543610edef9d374fa85a378edb573b47615f010000000000000074fa7381a7a74b316afb6793a00387eed9d95d46a69866cbb316b5d9c918af0e0100000000000000e0f0a776ecc9fa5e1f22e2fa001fe3fba5aea52b9444bc894b45589d4213247501000000000000006c4dd88b43e2011cf9a6a73d53446336ac9e04cdd4ca23587df63187ac455e4901000000000000003c944c704cae203619b9e7a5a4b6742736da6a8e76c762291bebdc7652cfec2f01000000000000002ff7c765405e9c11a59525a08173bb1fa59e5e281090f8e4d1824469f513d0cc01000000000000000400000000000000029b2e88b8ce43a677c1ca90f62134800b7e510c0c353dad719cad82faf6136cfb0d0e00000104000000000000000ea2e40800000000b00400000000000014daaaaab6a6e574099e24ae9bb75b543610edef9d374fa85a378edb573b47615f010000000000000074fa7381a7a74b316afb6793a00387eed9d95d46a69866cbb316b5d9c918af0e0100000000000000e0f0a776ecc9fa5e1f22e2fa001fe3fba5aea52b9444bc894b45589d4213247501000000000000006c4dd88b43e2011cf9a6a73d53446336ac9e04cdd4ca23587df63187ac455e4901000000000000003c944c704cae203619b9e7a5a4b6742736da6a8e76c762291bebdc7652cfec2f0100000000000000dea465ff8bf16938cc9ead89bf9fdb5d9c495fad61fd952b2067ebdc51c4e1c10100000000000000040000000000000002",
|
||||
"babeFinalizedBlockWeight": 1039,
|
||||
"finalizedBlockHeader": "0x6ed6c2debc2e5fd4e7db0d14426d1b904e6c101f2c62a71b8e891c217ba79079f9433280c0257a860f793833bd6bed6b9f86094400aa8e5ea24a81752f0f046ff5ed560f7231760c622ae35d3968fbab033ed34d950b57a7937ae45c411d1d384748080642414245b50103000000004fa0e40800000000a2c7d71b4e1f94c0208c9730ab93955b08c8d7ac86d2fc6ec5f62cc3272a5f1ec0e28c798461372109ee3e12f03ff66ea5ad9cac5b1c37d7280d2333d0226f0865ea77a801bad79785a8ca83c87f0dbf1e36936a6f65cd7b125a41c52f38f80105424142450101caaa6fe5f9df57930e2ac08aef43b75d5477d410c73c3a8e6dea9d5503b9fd25eae1d12b6604194389e22f3f4265d581eb162d1dc5a9034247fe33765dddbe8c",
|
||||
"grandpaAuthoritySet": "0x1455446f9a7aa99ced06b317c80ce90d56b84e56526775683af2525969e8da0b640100000000000000236d2fa03f4ed8cb65de7e514d7540159b328f1c170dd402b094ad7fbf5472180100000000000000b63c5a0cf342b9b04931bc8ed74d7d0165ab99ab5f8a4514797d4b299a4501fe01000000000000008f9ea20bf4a807a8e710f7559dece86e94672b5b361de157bdaa5c1f37849f8d01000000000000000aa3a88f6b777c95c3dfe7e997b76798413f16aa325f34824cae0c9102b281d5010000000000000000000000000000000001fe1000000000"
|
||||
},
|
||||
"name": "Casper Staging Testnet",
|
||||
"properties": {
|
||||
"ss58Format": 1996,
|
||||
"tokenDecimals": 18,
|
||||
"tokenSymbol": "CSPR"
|
||||
},
|
||||
"protocolId": "cspr",
|
||||
"telemetryEndpoints": [
|
||||
[
|
||||
"/dns/telemetry.ghostchain.io/tcp/443/x-parity-wss/%2Fsubmit%2F",
|
||||
0
|
||||
]
|
||||
]
|
||||
}`;
|
||||
@ -259,3 +259,40 @@ export const executeOnChainTransaction = async ({
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export const executePapiBareTransaction = async ({
|
||||
client,
|
||||
bareTx,
|
||||
messages = {
|
||||
loadingMsg: "Broadcasting transaction to available peers...",
|
||||
inBlockMsg: "Transaction included in block, waiting for finality...",
|
||||
successMsg: "Transaction successfully finalized!",
|
||||
errorMsg: "Transaction failed.",
|
||||
},
|
||||
}) => {
|
||||
try {
|
||||
return await new Promise((resolve, reject) => {
|
||||
const subscription = client.submitAndWatch(bareTx).subscribe({
|
||||
next: (event) => {
|
||||
if (event.type === "broadcasted") {
|
||||
toast.success(messages.loadingMsg);
|
||||
} else if (event.type === "inBestBlock") {
|
||||
toast.success(messages.inBlockMsg);
|
||||
} else if (event.type === "finalized") {
|
||||
toast.success(messages.successMsg);
|
||||
subscription.unsubscribe();
|
||||
resolve(event);
|
||||
}
|
||||
},
|
||||
error: (err) => {
|
||||
toast.error(`${messages.errorMsg} ${err.message || err}`);
|
||||
subscription.unsubscribe();
|
||||
reject(err);
|
||||
},
|
||||
});
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Bare PAPI Transaction failed:", err);
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
@ -17,38 +17,68 @@ import { DecimalBigNumber } from "../../helpers/DecimalBigNumber";
|
||||
import { executeOnChainTransaction, getTokenDecimals } from "../helpers";
|
||||
import { useCirculatingSupply } from "../tokens";
|
||||
|
||||
export const useWeaverState = (chainId, blockNumber, context) => {
|
||||
const { session, index } = context;
|
||||
export const useWeaverMaximumSlots = (chainId) => {
|
||||
const { gatekeeperAddress } = useGatekeeperAddress(chainId);
|
||||
|
||||
const { data: merkleRoot } = useReadContract({
|
||||
const { data } = useReadContract({
|
||||
abi: GatekeeperAbi,
|
||||
address: gatekeeperAddress,
|
||||
functionName: "getRoot",
|
||||
args: [index, blockNumber],
|
||||
scopeKey: `getRoot-${chainId}-${session}-${gatekeeperAddress}`,
|
||||
functionName: "SLOTS",
|
||||
scopeKey: `SLOTS-${chainId}-${gatekeeperAddress}`,
|
||||
chainId: chainId,
|
||||
});
|
||||
|
||||
const { data: merkleProof } = useReadContract({
|
||||
return { maximumSlots: data ? data : 1n };
|
||||
}
|
||||
|
||||
export const useWeaverRoot = (chainId, blockNumber, context) => {
|
||||
const session = context?.session;
|
||||
const { gatekeeperAddress } = useGatekeeperAddress(chainId);
|
||||
|
||||
const { data } = useReadContract({
|
||||
abi: GatekeeperAbi,
|
||||
address: gatekeeperAddress,
|
||||
functionName: "getRoot",
|
||||
args: [session, blockNumber],
|
||||
scopeKey: `getRoot-${chainId}-${session}-${blockNumber}-${gatekeeperAddress}`,
|
||||
chainId: chainId,
|
||||
});
|
||||
|
||||
return { merkleRoot: data?.at(0), nextSession: data?.at(1) }
|
||||
}
|
||||
|
||||
export const useWeaverProof = (chainId, blockNumber, context) => {
|
||||
const index = context?.index;
|
||||
const session = context?.session;
|
||||
const { gatekeeperAddress } = useGatekeeperAddress(chainId);
|
||||
|
||||
const { data: merkleProofInner } = useReadContract({
|
||||
abi: GatekeeperAbi,
|
||||
address: gatekeeperAddress,
|
||||
functionName: "getProof",
|
||||
args: [index, session, blockNumber],
|
||||
scopeKey: `getProof-${chainId}-${session}-${gatekeeperAddress}`,
|
||||
scopeKey: `getProof-${chainId}-${session}-${index}-${blockNumber}-${gatekeeperAddress}`,
|
||||
chainId: chainId,
|
||||
});
|
||||
|
||||
const { data: slotValues } = useReadContract({
|
||||
return { merkleProof: merkleProofInner }
|
||||
}
|
||||
|
||||
export const useWeaverSlotValues = (chainId, blockNumber, context) => {
|
||||
const index = context?.index;
|
||||
const session = context?.session;
|
||||
const { gatekeeperAddress } = useGatekeeperAddress(chainId);
|
||||
|
||||
const { data: slotValuesInner } = useReadContract({
|
||||
abi: GatekeeperAbi,
|
||||
address: gatekeeperAddress,
|
||||
functionName: "getSlotValues",
|
||||
args: [index, session, blockNumber],
|
||||
scopeKey: `getSlotValues-${chainId}-${session}-${gatekeeperAddress}`,
|
||||
scopeKey: `getSlotValues-${chainId}-${session}-${index}-${blockNumber}-${gatekeeperAddress}`,
|
||||
chainId: chainId,
|
||||
});
|
||||
|
||||
return null
|
||||
return { slotValues: slotValuesInner }
|
||||
}
|
||||
|
||||
export const useGatekeeperMinimum = (chainId) => {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user