diff --git a/src/app/components/transaction.tsx b/src/app/components/transaction.tsx
index 24e7e35..16bb2f2 100644
--- a/src/app/components/transaction.tsx
+++ b/src/app/components/transaction.tsx
@@ -8,7 +8,7 @@ import * as CLS from "@emurgo/cardano-serialization-lib-browser";
import ReactJsonPretty from 'react-json-pretty';
import * as txValidationUtils from "../utils/txValidationUtils";
import { TransactionChecks } from "./validationChecks";
-import { decodeHextoTx,convertGAToBech,getCardanoScanURL} from "../utils/txUtils";
+import { decodeHextoTx,convertGAToBech,getCardanoScanURL,getDataHashFromURI} from "../utils/txUtils";
import { VotingDetails } from "./votingDetails";
@@ -30,6 +30,7 @@ export const TransactionButton = () => {
isSameNetwork: false,
hasICCCredentials: false,
isInOutputPlutusData: false,
+ isMetadataAnchorValid: false,
});
const resetValidationState = () => {
setValidationState((prev) => ({
@@ -40,6 +41,7 @@ export const TransactionButton = () => {
isSameNetwork: false,
hasICCCredentials: false,
isInOutputPlutusData: false,
+ isMetadataAnchorValid: false,
}));
};
@@ -89,8 +91,12 @@ export const TransactionButton = () => {
const voting_procedures= transactionBody.to_js_value().voting_procedures;
if (!voting_procedures) throw new Error("Transaction has no voting procedures.");
const votes=voting_procedures[0].votes;
+ if (!votes) throw new Error("Transaction has no votes.");
const hasOneVote = txValidationUtils.hasOneVoteOnTransaction(transactionBody);
const vote = voting_procedures[0].votes[0].voting_procedure.vote;
+ if(!votes[0].voting_procedure.anchor) throw new Error("Vote has no anchor.");
+ const voteMetadataURL = votes[0].voting_procedure.anchor.anchor_url;
+ const voteMetadataHash = votes[0].voting_procedure.anchor.anchor_data_hash;
setValidationState({
isPartOfSigners: await txValidationUtils.isPartOfSigners(transactionBody, stakeCred),
@@ -99,6 +105,7 @@ export const TransactionButton = () => {
isSameNetwork: txValidationUtils.isSameNetwork(transactionBody, network),
hasICCCredentials: txValidationUtils.hasValidICCCredentials(transactionBody, network),
isInOutputPlutusData: txValidationUtils.isSignerInPlutusData(transactionBody, stakeCred),
+ isMetadataAnchorValid: await txValidationUtils.checkMetadataAnchor(voteMetadataURL,voteMetadataHash),
});
//********************************************Voting Details *********************************************************************/
@@ -108,13 +115,15 @@ export const TransactionButton = () => {
if (votes && hasOneVote) {
const govActionID = convertGAToBech(votes[0].action_id.transaction_id, votes[0].action_id.index);
+
setvoteChoice(vote === 'Yes' ? 'Constitutional' : vote === 'No' ? 'Unconstitutional' : 'Abstain');
setgovActionID(govActionID);
if(!votes[0].voting_procedure.anchor) throw new Error("Vote has no anchor.");
- setmetadataAnchorURL(votes[0].voting_procedure.anchor.anchor_url);
- setMetadataAnchorHash(votes[0].voting_procedure.anchor.anchor_data_hash);
+ setmetadataAnchorURL(voteMetadataURL);
+ setMetadataAnchorHash(voteMetadataHash);
setCardanoscan(getCardanoScanURL(govActionID,transactionNetworkID));
- }
+ }
+
}
diff --git a/src/app/components/validationChecks.tsx b/src/app/components/validationChecks.tsx
index af52c70..4bb8bbc 100644
--- a/src/app/components/validationChecks.tsx
+++ b/src/app/components/validationChecks.tsx
@@ -7,6 +7,7 @@ interface TransactionChecksProps {
isSameNetwork: boolean;
hasICCCredentials: boolean;
isInOutputPlutusData: boolean;
+ isMetadataAnchorValid: boolean;
}
export const TransactionChecks = ({
@@ -16,6 +17,7 @@ export const TransactionChecks = ({
isSameNetwork,
hasICCCredentials,
isInOutputPlutusData,
+ isMetadataAnchorValid,
}: TransactionChecksProps) => {
return (
@@ -43,6 +45,10 @@ export const TransactionChecks = ({
Is stake credential in plutus data?: {isInOutputPlutusData ? "✅" : "❌"}
+
+
+ Does the metadata match the provided hash? ?: {isMetadataAnchorValid ? "✅" : "❌"}
+
);
diff --git a/src/app/utils/txUtils.ts b/src/app/utils/txUtils.ts
index f3d3ba5..4492a97 100644
--- a/src/app/utils/txUtils.ts
+++ b/src/app/utils/txUtils.ts
@@ -1,6 +1,7 @@
import * as CLS from "@emurgo/cardano-serialization-lib-browser";
import { deserializeAddress } from "@meshsdk/core";
import dotevn from "dotenv";
+import * as blake from 'blakejs';
dotevn.config();
const NEXT_PUBLIC_REST_IPFS_GATEWAY=process.env.NEXT_PUBLIC_REST_IPFS_GATEWAY;
@@ -62,4 +63,23 @@ export const openInNewTab = (url: string) => {
? "https://" + NEXT_PUBLIC_REST_IPFS_GATEWAY + url?.slice(7)
: "https://" + url;
window.open(fullUrl, "_blank", "noopener,noreferrer");
-};
\ No newline at end of file
+};
+
+export const getDataHashFromURI = async (anchorURL: string) => {
+ console.log('Callllll fuuunctioooon');
+ if (anchorURL !== "") {
+ console.log("Anchor data null")
+ }
+ if (anchorURL.startsWith("ipfs")) {
+ anchorURL = "https://" + NEXT_PUBLIC_REST_IPFS_GATEWAY + anchorURL.slice(7);
+ }
+ // anchorURL='https://ipfs.io/ipfs/bafkreidsmyjjfrsvj3czrsu5roy2undco2bhhcnqdgbievolgbyi7lptxy'
+ const data = await fetch(anchorURL);
+ const text = await data.text();
+ console.log('THEEEEE TEXT',text);
+ const hash = blake.blake2bHex(text,undefined, 32);
+ console.log("Hash from text:", hash);
+ return hash
+}
+
+
diff --git a/src/app/utils/txValidationUtils.ts b/src/app/utils/txValidationUtils.ts
index 2eb5c71..5b2f425 100644
--- a/src/app/utils/txValidationUtils.ts
+++ b/src/app/utils/txValidationUtils.ts
@@ -1,3 +1,5 @@
+import {getDataHashFromURI} from "../utils/txUtils";
+
/**
* Checks if the given stake credential is part of the required signers of the transaction.
* @param transactionBody the body of the transaction to check.
@@ -156,3 +158,18 @@ export const isSignerInPlutusData = (transactionBody: any, stakeCredential: stri
return false;
};
+/**
+ * Checks if the given anchor URL produces the given anchor data hash.
+ * @param anchorURL The URL of the anchor to check.
+ * @param anchor_data_hash The expected anchor data hash.
+ * @returns {Promise} True if the anchor URL produces the expected hash, false otherwise.
+ */
+export const checkMetadataAnchor = async (anchorURL: string, anchor_data_hash: string): Promise => {
+ try {
+ const producedHash = await getDataHashFromURI(anchorURL);
+ return producedHash === anchor_data_hash;
+ } catch (error) {
+ console.error("Error fetching metadata:", error);
+ return false;
+ }
+};