From 75073cfb086a9ff78db12fdc88842712f501d120 Mon Sep 17 00:00:00 2001 From: Elena Bardho Date: Wed, 22 Jan 2025 16:25:58 +0000 Subject: [PATCH 1/6] Add new transaction validations --- src/.gitignore | 3 +- src/app/components/transaction.tsx | 63 +++++++++++++++++++++++++----- 2 files changed, 55 insertions(+), 11 deletions(-) diff --git a/src/.gitignore b/src/.gitignore index ee38336..3f75d2e 100644 --- a/src/.gitignore +++ b/src/.gitignore @@ -38,4 +38,5 @@ yarn-error.log* next-env.d.ts #test files -test.js \ No newline at end of file +test.js +/test \ No newline at end of file diff --git a/src/app/components/transaction.tsx b/src/app/components/transaction.tsx index 4d09120..2ffaabb 100644 --- a/src/app/components/transaction.tsx +++ b/src/app/components/transaction.tsx @@ -27,6 +27,9 @@ export const TransactionButton = () => { const { wallet, connected, name, connect, disconnect } = useWallet(); const [signature, setsignature] = useState(""); const [isPartOfSigners, setIsPartOfSigners] = useState(false); + const [isOneVote, setIsOneVote] = useState(false); + const [hasCertificates, setHasCertificates] = useState(false); + const [isSameNetwork, setIsSameNetwork] = useState(false); @@ -51,19 +54,59 @@ export const TransactionButton = () => { console.log("Payment Credential:", paymentCred); console.log("Stake Credential:", stakeCred); - const requiredSigners = unsignedTransaction?.body().required_signers(); - console.log("Required signers in the transaction:", requiredSigners?.to_json()); + //**************************************Validation Checks**************************************** - if (!requiredSigners || requiredSigners.len() === 0) { - console.log("No required signers in the transaction."); - - } else if (requiredSigners?.to_json().includes(stakeCred) || requiredSigners?.to_json().includes(paymentCred)) { - console.log("Required signers in the transaction:", requiredSigners?.to_json()); - setIsPartOfSigners(true); - } + const transactionBody = unsignedTransaction?.body(); + try{ + const transactionBody = unsignedTransaction?.body(); + if (!transactionBody) { + throw new Error("Transaction body is null."); + } + //wallet needs to sign + const requiredSigners = transactionBody.required_signers(); + if (!requiredSigners || requiredSigners.len() === 0) { + console.log("No required signers in the transaction."); + + } else if (requiredSigners?.to_json().includes(stakeCred) || requiredSigners?.to_json().includes(paymentCred)) { + console.log("Required signers in the transaction:", requiredSigners?.to_json()); + setIsPartOfSigners(true); + } + //one vote + + const votesNumber = unsignedTransaction?.body()?.to_js_value().voting_procedures?.[0]?.votes?.length || -1; + if(votesNumber === 1){ + setIsOneVote(true); + console.log("Transaction has one vote."); + }else if (votesNumber < 0){ + throw new Error("Transaction has no votes."); + }else{ + throw new Error("You are signing more than one vote. Number of votes: "+ votesNumber); + } + + // No certificates + const certificates = unsignedTransaction?.body()?.certs() || null; + console.log("certificates:", certificates); + if (certificates === null) { + console.log("No certificates in the transaction."); + setHasCertificates(true); + } + //Same network + const transactionNetworkID= transactionBody.outputs().get(0).address().to_bech32().startsWith("addr_test1")?0:1; + console.log('transactionNetwork:',transactionNetworkID); + if (network === transactionNetworkID ) { + setIsSameNetwork(true); + } + + //Is Intersect CC credential + //for future add context of some of the + } + catch (error) { + console.error("Error validating transaction:", error); + } + }; const signTransaction = async () => { @@ -81,7 +124,7 @@ export const TransactionButton = () => { } catch (error) { console.error("Error signing transaction:", error); - setMessage("Transaction signing failed. Check the console for more details."); + setMessage("Transaction signing failed. " + error); } }; From 4914224764fa5f709a6eb04ecb620dae790ad2a9 Mon Sep 17 00:00:00 2001 From: Elena Bardho Date: Fri, 24 Jan 2025 16:37:11 +0000 Subject: [PATCH 2/6] Add validation checks for plutus data and ICC credential --- src/app/components/transaction.tsx | 68 ++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 8 deletions(-) diff --git a/src/app/components/transaction.tsx b/src/app/components/transaction.tsx index 2ffaabb..6561165 100644 --- a/src/app/components/transaction.tsx +++ b/src/app/components/transaction.tsx @@ -30,6 +30,8 @@ export const TransactionButton = () => { const [isOneVote, setIsOneVote] = useState(false); const [hasCertificates, setHasCertificates] = useState(false); const [isSameNetwork, setIsSameNetwork] = useState(false); + const [hasICCCredentials, setHasICCCredentials] = useState(false); + const [isInOutputPlutusData , setIsInOutputPlutusData] = useState(false); @@ -55,15 +57,16 @@ export const TransactionButton = () => { console.log("Payment Credential:", paymentCred); console.log("Stake Credential:", stakeCred); - //**************************************Validation Checks**************************************** + //**************************************Transaction Validation Checks**************************************** const transactionBody = unsignedTransaction?.body(); + const voting_procedures= transactionBody?.to_js_value().voting_procedures; try{ - const transactionBody = unsignedTransaction?.body(); if (!transactionBody) { throw new Error("Transaction body is null."); } //wallet needs to sign + // Check if signer part of plutus output data const requiredSigners = transactionBody.required_signers(); if (!requiredSigners || requiredSigners.len() === 0) { console.log("No required signers in the transaction."); @@ -71,24 +74,24 @@ export const TransactionButton = () => { } else if (requiredSigners?.to_json().includes(stakeCred) || requiredSigners?.to_json().includes(paymentCred)) { console.log("Required signers in the transaction:", requiredSigners?.to_json()); setIsPartOfSigners(true); - } + } //one vote - const votesNumber = unsignedTransaction?.body()?.to_js_value().voting_procedures?.[0]?.votes?.length || -1; + const votesNumber = voting_procedures?.[0]?.votes?.length || -1; if(votesNumber === 1){ setIsOneVote(true); console.log("Transaction has one vote."); }else if (votesNumber < 0){ throw new Error("Transaction has no votes."); }else{ - throw new Error("You are signing more than one vote. Number of votes: "+ votesNumber); + //throw new Error("You are signing more than one vote. Number of votes: "+ votesNumber); } // No certificates - const certificates = unsignedTransaction?.body()?.certs() || null; + const certificates = transactionBody?.certs(); console.log("certificates:", certificates); - if (certificates === null) { + if (!certificates) { console.log("No certificates in the transaction."); setHasCertificates(true); } @@ -100,7 +103,55 @@ export const TransactionButton = () => { setIsSameNetwork(true); } + //Is Intersect CC credential + const voterJSON = voting_procedures?.[0]?.voter; + console.log("voterJSON:", voterJSON); + let key = ""; + function isConstitutionalCommitteeHotCred(voter: CLS.VoterJSON): voter is { ConstitutionalCommitteeHotCred: { Script: string } } { + return (voter as { ConstitutionalCommitteeHotCred: any }).ConstitutionalCommitteeHotCred !== undefined; + } + if (voterJSON && isConstitutionalCommitteeHotCred(voterJSON)) { + // If it has ConstitutionalCommitteeHotCred, extract the Script hex + const credType = voterJSON.ConstitutionalCommitteeHotCred; + key = credType.Script; + console.log("ConstitutionalCommitteeHotCred Key:", key); + } + if (network === 0 && key === "4f00984fa72e265b8ff8ffce4405da562cd3d6b16a4a38de3372eeea") { + console.log("Intersect CC Credential found in testnet"); + setHasICCCredentials(true); + } else if (network === 1 && key === "85c47dd4b9a2e70e88965d91dd69be182d5605b23bb5250b1c94bf64") { + console.log("Intersect CC Credential found in mainnet"); + setHasICCCredentials(true); + } else { + console.error("Incorrect Intersect CC Credentials"); + } + //plutus + const plutusScripts = transactionBody?.outputs().to_js_value(); + console.log("plutusScripts:", plutusScripts); + + if (Array.isArray(plutusScripts)) { + const regex = new RegExp(signature); + plutusScripts.forEach((output, index) => { + if (output.plutus_data && typeof output.plutus_data === 'object' && 'Data' in output.plutus_data) { + const plutusData = output.plutus_data.Data; + console.log("plutusData:", plutusData); + if (regex.test(plutusData)) { + console.log(`Signature found in output ${index}`); + setIsInOutputPlutusData(true); + } + } else if (!output.plutus_data) { + console.log(`No plutus data found in output`); + } else { + console.log(`Signiture not found on plutus script data`); + } + }); + + } else { + console.error("Transaction outputs are not available "); + } + + //for future add context of some of the } catch (error) { @@ -108,7 +159,7 @@ export const TransactionButton = () => { } }; - + const signTransaction = async () => { console.log("isPartOfSigners:", isPartOfSigners); try { @@ -119,6 +170,7 @@ export const TransactionButton = () => { const signature = await decodeTransaction(signedTx); setsignature(signature?.witness_set().vkeys()?.get(0)?.signature()?.to_hex() || ''); console.log("signature:", signature?.witness_set().vkeys()?.get(0).signature().to_hex()); + } else { throw new Error("You are not part of the required signers."); } From ebecaa919ff4518f1199fb1910598c847ab4550f Mon Sep 17 00:00:00 2001 From: elenabardho <71819187+elenabardho@users.noreply.github.com> Date: Fri, 24 Jan 2025 17:06:16 +0000 Subject: [PATCH 3/6] Update src/app/components/transaction.tsx Co-authored-by: Ryan --- src/app/components/transaction.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/transaction.tsx b/src/app/components/transaction.tsx index 6561165..8864233 100644 --- a/src/app/components/transaction.tsx +++ b/src/app/components/transaction.tsx @@ -88,7 +88,7 @@ export const TransactionButton = () => { //throw new Error("You are signing more than one vote. Number of votes: "+ votesNumber); } - // No certificates + // Check to see if the transactions has any certificates in it const certificates = transactionBody?.certs(); console.log("certificates:", certificates); if (!certificates) { From 0daa9fb4fe764b6190d99d68fcca8f5dc6135e53 Mon Sep 17 00:00:00 2001 From: elenabardho <71819187+elenabardho@users.noreply.github.com> Date: Fri, 24 Jan 2025 17:07:16 +0000 Subject: [PATCH 4/6] Update src/app/components/transaction.tsx Co-authored-by: Ryan --- src/app/components/transaction.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/transaction.tsx b/src/app/components/transaction.tsx index 8864233..237151c 100644 --- a/src/app/components/transaction.tsx +++ b/src/app/components/transaction.tsx @@ -107,7 +107,7 @@ export const TransactionButton = () => { //Is Intersect CC credential const voterJSON = voting_procedures?.[0]?.voter; console.log("voterJSON:", voterJSON); - let key = ""; + let key; function isConstitutionalCommitteeHotCred(voter: CLS.VoterJSON): voter is { ConstitutionalCommitteeHotCred: { Script: string } } { return (voter as { ConstitutionalCommitteeHotCred: any }).ConstitutionalCommitteeHotCred !== undefined; } From 0573334af0d1d8fbdff8879f739f080048e178f4 Mon Sep 17 00:00:00 2001 From: Elena Bardho Date: Fri, 24 Jan 2025 17:55:43 +0000 Subject: [PATCH 5/6] Small improvements --- src/app/components/transaction.tsx | 36 +++++++++++++++++------------- 1 file changed, 21 insertions(+), 15 deletions(-) diff --git a/src/app/components/transaction.tsx b/src/app/components/transaction.tsx index 237151c..cd7b611 100644 --- a/src/app/components/transaction.tsx +++ b/src/app/components/transaction.tsx @@ -51,10 +51,8 @@ export const TransactionButton = () => { console.log("unsignedTransaction:", unsignedTransaction); const changeAddress = await wallet.getChangeAddress(); - const paymentCred = deserializeAddress(changeAddress).pubKeyHash; const stakeCred = deserializeAddress(changeAddress).stakeCredentialHash; - console.log("Payment Credential:", paymentCred); console.log("Stake Credential:", stakeCred); //**************************************Transaction Validation Checks**************************************** @@ -71,18 +69,18 @@ export const TransactionButton = () => { if (!requiredSigners || requiredSigners.len() === 0) { console.log("No required signers in the transaction."); - } else if (requiredSigners?.to_json().includes(stakeCred) || requiredSigners?.to_json().includes(paymentCred)) { + } else if (requiredSigners?.to_json().includes(stakeCred) ) { console.log("Required signers in the transaction:", requiredSigners?.to_json()); setIsPartOfSigners(true); } //one vote - const votesNumber = voting_procedures?.[0]?.votes?.length || -1; + const votesNumber = voting_procedures?.[0]?.votes?.length; if(votesNumber === 1){ setIsOneVote(true); console.log("Transaction has one vote."); - }else if (votesNumber < 0){ + }else if (!votesNumber){ throw new Error("Transaction has no votes."); }else{ //throw new Error("You are signing more than one vote. Number of votes: "+ votesNumber); @@ -107,43 +105,51 @@ export const TransactionButton = () => { //Is Intersect CC credential const voterJSON = voting_procedures?.[0]?.voter; console.log("voterJSON:", voterJSON); - let key; + let script; + // Function to check if the voterJSON has ConstitutionalCommitteeHotCred to avoid type error function isConstitutionalCommitteeHotCred(voter: CLS.VoterJSON): voter is { ConstitutionalCommitteeHotCred: { Script: string } } { return (voter as { ConstitutionalCommitteeHotCred: any }).ConstitutionalCommitteeHotCred !== undefined; } + if (voterJSON && isConstitutionalCommitteeHotCred(voterJSON)) { // If it has ConstitutionalCommitteeHotCred, extract the Script hex const credType = voterJSON.ConstitutionalCommitteeHotCred; - key = credType.Script; - console.log("ConstitutionalCommitteeHotCred Key:", key); + script = credType.Script; + console.log("ConstitutionalCommitteeHotCred Script:", script); + } - if (network === 0 && key === "4f00984fa72e265b8ff8ffce4405da562cd3d6b16a4a38de3372eeea") { + //If in Testnet and scrit matches preview ICC credential ; else if in mainnet and script matches mainnet ICC credential + if (network === 0 && script === "4f00984fa72e265b8ff8ffce4405da562cd3d6b16a4a38de3372eeea") { console.log("Intersect CC Credential found in testnet"); setHasICCCredentials(true); - } else if (network === 1 && key === "85c47dd4b9a2e70e88965d91dd69be182d5605b23bb5250b1c94bf64") { + } else if (network === 1 && script === "85c47dd4b9a2e70e88965d91dd69be182d5605b23bb5250b1c94bf64") { console.log("Intersect CC Credential found in mainnet"); setHasICCCredentials(true); } else { console.error("Incorrect Intersect CC Credentials"); } - //plutus + //check if signer is in plutus data const plutusScripts = transactionBody?.outputs().to_js_value(); console.log("plutusScripts:", plutusScripts); + console.log("stakeCred:", stakeCred); + + if (Array.isArray(plutusScripts) && stakeCred) { - if (Array.isArray(plutusScripts)) { - const regex = new RegExp(signature); + const regex = new RegExp(stakeCred); + plutusScripts.forEach((output, index) => { if (output.plutus_data && typeof output.plutus_data === 'object' && 'Data' in output.plutus_data) { const plutusData = output.plutus_data.Data; console.log("plutusData:", plutusData); + if (regex.test(plutusData)) { - console.log(`Signature found in output ${index}`); + console.log(`Stake credential found in output for address ${output.address}`); setIsInOutputPlutusData(true); } } else if (!output.plutus_data) { console.log(`No plutus data found in output`); } else { - console.log(`Signiture not found on plutus script data`); + console.log(`Stake credential not found on plutus script data for address ${output.address}`); } }); From a3aed796e56c2022f7e13435973f3af322f3069a Mon Sep 17 00:00:00 2001 From: Elena Bardho Date: Mon, 27 Jan 2025 10:26:14 +0000 Subject: [PATCH 6/6] Fix lint warnings --- src/app/components/wallet.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/components/wallet.tsx b/src/app/components/wallet.tsx index ea8d03c..2ffae9e 100644 --- a/src/app/components/wallet.tsx +++ b/src/app/components/wallet.tsx @@ -50,7 +50,7 @@ export const Wallet = () => { }; handleWalletConnection(); - }, [wallet,connected, name, ,paymentCred, stakeCred]); + }, [wallet,connected, name]); return ; };