From f40d4d070c6549023f037c3c4cb58fbb2dd9c9a6 Mon Sep 17 00:00:00 2001 From: sara Date: Fri, 5 Apr 2024 13:38:17 -0300 Subject: [PATCH 01/16] feat: validations component options and validation interface --- web/app/components.tsx | 247 ++++++++++++++++++++++++++++++++++++----- web/app/routes/tx.tsx | 75 ++++++++++++- 2 files changed, 292 insertions(+), 30 deletions(-) diff --git a/web/app/components.tsx b/web/app/components.tsx index 33bf159..fb3db7b 100644 --- a/web/app/components.tsx +++ b/web/app/components.tsx @@ -1,5 +1,6 @@ -import { PropsWithChildren } from "react"; import { Attribute, type Section } from "napi-pallas"; +import { PropsWithChildren, useState } from "react"; +import { IValidation } from "./routes/tx"; export type TopicMeta = { title: string; @@ -43,7 +44,7 @@ export function HexBlock(props: { name: string; value: string }) { ); } -export function Paragraph(props: PropsWithChildren<{}>) { +export function Paragraph(props: PropsWithChildren) { return

{props.children}

; } @@ -59,13 +60,11 @@ export function RootSection(props: { <>

{topic.title}

{!props.data.error && topic.description} - {!!props.data.error && (
{props.data.error}
)} - {!!props.data.bytes && ( )} @@ -84,30 +83,46 @@ export function DataSection(props: { topics: Record; }) { const topic = getTopicMeta(props.data.topic, props.topics); + const [open, setOpen] = useState(true); + const handleClick = () => setOpen(!open); return (
-

{topic.title}

- {topic.description} - {!!props.data.error && ( -
- {props.data.error} + + {open && ( + <> + {topic.description} + {!!props.data.error && ( +
+ {props.data.error} +
+ )} + {props.data.attributes?.map((c) => ( + + ))} + {props.data.children?.map((c) => ( + + ))} + {!props.data.attributes?.length && !props.data.children?.length && ( + + )} + {!!props.data.bytes && ( + + )} + )}
); @@ -145,7 +160,7 @@ export function TextArea(props: { name: string; placeholder?: string }) { } export function logCuriosity(data: any) { - if (!!data) { + if (data) { console.group("CURIOUS FELLOW, EH?"); console.log("hello there! want to learn how we parse the data?"); console.log( @@ -159,3 +174,185 @@ export function logCuriosity(data: any) { console.groupEnd(); } } + +export function ValidationTable(props: { validations: IValidation[] }) { + return ( + + + + + + + + + + {props.validations.map((v) => ( + + + + + + ))} + +
+ Validation + + Result + + Description +
+ {v.name} + + {v.value ? " ✔" : "✘"} + + {v.description} +
+ ); +} + +export function ValidationCards(props: { validations: IValidation[] }) { + return ( +
+ {props.validations.map((v) => ( +
+

+ {v.value ? "✔" : "✘"} {v.name} +

+

+ {v.description !== "" ? v.description : "Successful"} +

+
+ ))} +
+ ); +} + +export function AccordionItem2({ validation }: { validation: IValidation }) { + const [open, setOpen] = useState(false); + const handleClick = () => setOpen(!open); + return ( +
+
+ +
+ + +
+
+ {open && ( +
+

+ {validation.description !== "" + ? validation.description + : "Successful"} +

+
+ )} +
+ ); +} + +export function ValidationAccordion2(props: { validations: IValidation[] }) { + return ( +
+ {props.validations.map((v) => ( + + ))} +
+ ); +} + +export function AccordionItem({ validation }: { validation: IValidation }) { + const [open, setOpen] = useState(false); + const handleClick = () => setOpen(!open); + return ( +
+
+ +
+ + +
+
+
+ {open && ( +

{validation.description}

+ )} +
+
+ ); +} + +export function ValidationAccordion(props: { validations: IValidation[] }) { + return ( +
+ {props.validations.map((v) => ( + + ))} +
+ ); +} diff --git a/web/app/routes/tx.tsx b/web/app/routes/tx.tsx index d88b14b..79ba8eb 100644 --- a/web/app/routes/tx.tsx +++ b/web/app/routes/tx.tsx @@ -1,9 +1,22 @@ import { ActionFunctionArgs, json, type MetaFunction } from "@remix-run/node"; import { Form, useActionData } from "@remix-run/react"; -import { Button, logCuriosity, RootSection } from "~/components"; +import { + Button, + logCuriosity, + RootSection, + ValidationAccordion, + ValidationCards, + ValidationTable, +} from "../components"; import * as server from "./tx.server"; import TOPICS from "./tx.topics"; +export interface IValidation { + name: string; + value: boolean; + description: string; +} + export const meta: MetaFunction = () => { return [ { title: "Cardano Tx - Lovelace Anatomy" }, @@ -13,9 +26,9 @@ export const meta: MetaFunction = () => { export async function action({ request }: ActionFunctionArgs) { const formData = await request.formData(); - let raw = formData.get("raw"); + const raw = formData.get("raw"); - if (!!raw) { + if (raw) { const res = server.safeParseTx(raw.toString()); return json({ ...res, raw }); } else { @@ -41,10 +54,54 @@ function ExampleCard(props: { title: string; address: string }) { } export default function Index() { - const data: any = useActionData(); + const data = useActionData(); logCuriosity(data); + const validations: IValidation[] = [ + { name: "Non empty inputs", value: true, description: "" }, + { + name: "All inputs in utxos", + value: false, + description: + "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", + }, + { name: "Validity interval", value: true, description: "" }, + { name: "Fee", value: true, description: "" }, + { + name: "Preservation of value", + value: false, + description: + "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", + }, + { + name: "Min lovelace per UTxO", + value: false, + description: + "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", + }, + { name: "Output value size", value: true, description: "" }, + { name: "Network Id", value: true, description: "" }, + { name: "Tx size", value: true, description: "" }, + { name: "Tx execution units", value: true, description: "" }, + { name: "Minting", value: true, description: "" }, + { + name: "Well formed", + value: false, + description: + "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", + }, + { name: "Script witness", value: true, description: "" }, + { name: "Languages", value: true, description: "" }, + { + name: "Auxiliary data hash", + value: false, + description: + "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", + }, + { name: "Script data hash", value: true, description: "" }, + ]; + return (

Cardano Tx

@@ -82,7 +139,15 @@ export default function Index() { )} - {!!data && } + {!!data && ( + <> +

Tx Validations

+ + + + + + )}
); } From 4c9265b4498c4f4d0cb621748b1d552a7ab68a54 Mon Sep 17 00:00:00 2001 From: sara Date: Fri, 5 Apr 2024 14:29:21 -0300 Subject: [PATCH 02/16] feat: remove unused components and add collapsible to tx validations section --- web/app/components.tsx | 120 ----------------------------------------- web/app/routes/tx.tsx | 54 ++++++++++++------- 2 files changed, 35 insertions(+), 139 deletions(-) diff --git a/web/app/components.tsx b/web/app/components.tsx index fb3db7b..aad70cb 100644 --- a/web/app/components.tsx +++ b/web/app/components.tsx @@ -175,126 +175,6 @@ export function logCuriosity(data: any) { } } -export function ValidationTable(props: { validations: IValidation[] }) { - return ( - - - - - - - - - - {props.validations.map((v) => ( - - - - - - ))} - -
- Validation - - Result - - Description -
- {v.name} - - {v.value ? " ✔" : "✘"} - - {v.description} -
- ); -} - -export function ValidationCards(props: { validations: IValidation[] }) { - return ( -
- {props.validations.map((v) => ( -
-

- {v.value ? "✔" : "✘"} {v.name} -

-

- {v.description !== "" ? v.description : "Successful"} -

-
- ))} -
- ); -} - -export function AccordionItem2({ validation }: { validation: IValidation }) { - const [open, setOpen] = useState(false); - const handleClick = () => setOpen(!open); - return ( -
-
- -
- + -
-
- {open && ( -
-

- {validation.description !== "" - ? validation.description - : "Successful"} -

-
- )} -
- ); -} - -export function ValidationAccordion2(props: { validations: IValidation[] }) { - return ( -
- {props.validations.map((v) => ( - - ))} -
- ); -} - export function AccordionItem({ validation }: { validation: IValidation }) { const [open, setOpen] = useState(false); const handleClick = () => setOpen(!open); diff --git a/web/app/routes/tx.tsx b/web/app/routes/tx.tsx index 79ba8eb..bc4b149 100644 --- a/web/app/routes/tx.tsx +++ b/web/app/routes/tx.tsx @@ -1,12 +1,11 @@ import { ActionFunctionArgs, json, type MetaFunction } from "@remix-run/node"; import { Form, useActionData } from "@remix-run/react"; +import { useState } from "react"; import { Button, logCuriosity, RootSection, ValidationAccordion, - ValidationCards, - ValidationTable, } from "../components"; import * as server from "./tx.server"; import TOPICS from "./tx.topics"; @@ -17,6 +16,10 @@ export interface IValidation { description: string; } +export interface IValidations { + validations: IValidation[]; +} + export const meta: MetaFunction = () => { return [ { title: "Cardano Tx - Lovelace Anatomy" }, @@ -56,18 +59,21 @@ function ExampleCard(props: { title: string; address: string }) { export default function Index() { const data = useActionData(); + const [open, setOpen] = useState(false); + const handleClick = () => setOpen(!open); + logCuriosity(data); const validations: IValidation[] = [ - { name: "Non empty inputs", value: true, description: "" }, + { name: "Non empty inputs", value: true, description: "Sucessful" }, { name: "All inputs in utxos", value: false, description: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", }, - { name: "Validity interval", value: true, description: "" }, - { name: "Fee", value: true, description: "" }, + { name: "Validity interval", value: true, description: "Sucessful" }, + { name: "Fee", value: true, description: "Sucessful" }, { name: "Preservation of value", value: false, @@ -80,26 +86,26 @@ export default function Index() { description: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", }, - { name: "Output value size", value: true, description: "" }, - { name: "Network Id", value: true, description: "" }, - { name: "Tx size", value: true, description: "" }, - { name: "Tx execution units", value: true, description: "" }, - { name: "Minting", value: true, description: "" }, + { name: "Output value size", value: true, description: "Successful" }, + { name: "Network Id", value: true, description: "Successful" }, + { name: "Tx size", value: true, description: "Successful" }, + { name: "Tx execution units", value: true, description: "Successful" }, + { name: "Minting", value: true, description: "Successful" }, { name: "Well formed", value: false, description: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", }, - { name: "Script witness", value: true, description: "" }, - { name: "Languages", value: true, description: "" }, + { name: "Script witness", value: true, description: "Successful" }, + { name: "Languages", value: true, description: "Successful" }, { name: "Auxiliary data hash", value: false, description: "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", }, - { name: "Script data hash", value: true, description: "" }, + { name: "Script data hash", value: true, description: "Successful" }, ]; return ( @@ -140,13 +146,23 @@ export default function Index() { )} {!!data && ( - <> -

Tx Validations

- - - +
+
+ + {open && } +
- +
)} ); From f1829d70123eb8e866469cc343b53c63919abda7 Mon Sep 17 00:00:00 2001 From: sara Date: Fri, 5 Apr 2024 15:33:10 -0300 Subject: [PATCH 03/16] feat: structure of validate txs and eras validation scaffolding --- napi-pallas/Cargo.toml | 2 +- napi-pallas/index.d.ts | 14 +- napi-pallas/src/lib.rs | 73 +++- napi-pallas/src/tx.rs | 40 +- napi-pallas/src/validations/alonzo.rs | 8 + napi-pallas/src/validations/babbage.rs | 24 + napi-pallas/src/validations/byron.rs | 6 + napi-pallas/src/validations/conway.rs | 7 + napi-pallas/src/validations/mod.rs | 6 + napi-pallas/src/validations/shelley_ma.rs | 8 + napi-pallas/src/validations/validate.rs | 31 ++ web/app/routes/tx.server.ts | 2 +- web/yarn.lock | 509 +++++++++------------- 13 files changed, 408 insertions(+), 322 deletions(-) create mode 100644 napi-pallas/src/validations/alonzo.rs create mode 100644 napi-pallas/src/validations/babbage.rs create mode 100644 napi-pallas/src/validations/byron.rs create mode 100644 napi-pallas/src/validations/conway.rs create mode 100644 napi-pallas/src/validations/mod.rs create mode 100644 napi-pallas/src/validations/shelley_ma.rs create mode 100644 napi-pallas/src/validations/validate.rs diff --git a/napi-pallas/Cargo.toml b/napi-pallas/Cargo.toml index 41bbf9d..cf2d72f 100644 --- a/napi-pallas/Cargo.toml +++ b/napi-pallas/Cargo.toml @@ -12,7 +12,7 @@ hex = "0.4.3" # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix napi = { version = "2.12.2", default-features = false, features = ["napi4"] } napi-derive = "2.12.2" -pallas = "0.21.0" +pallas = { git = "https://github.com/alegadea/pallas.git", rev = "54ffc77" , features = ["unstable"]} [build-dependencies] napi-build = "2.0.1" diff --git a/napi-pallas/index.d.ts b/napi-pallas/index.d.ts index 4399f32..7254742 100644 --- a/napi-pallas/index.d.ts +++ b/napi-pallas/index.d.ts @@ -33,5 +33,17 @@ export interface Section { children: Array
} export function parseAddress(raw: string): Output -export function safeParseTx(raw: string): Section +export interface SectionValidation { + section: Section + validations: Validations +} +export function safeParseTx(raw: string): SectionValidation export function safeParseBlock(raw: string): Section +export interface Validation { + name: string + value: boolean + description: string +} +export interface Validations { + validations: Array +} diff --git a/napi-pallas/src/lib.rs b/napi-pallas/src/lib.rs index ffab29e..af1cc3a 100644 --- a/napi-pallas/src/lib.rs +++ b/napi-pallas/src/lib.rs @@ -8,6 +8,7 @@ extern crate napi_derive; mod address; mod block; mod tx; +mod validations; #[derive(Default)] #[napi(object)] @@ -143,11 +144,27 @@ pub fn parse_address(raw: String) -> address::Output { } } +#[derive(Default)] +#[napi(object)] +pub struct SectionValidation { + pub section: Section, + pub validations: Validations, +} + #[napi] -pub fn safe_parse_tx(raw: String) -> Section { +pub fn safe_parse_tx(raw: String) -> SectionValidation { match tx::parse(raw) { - Ok(x) => x, - Err(x) => x, + Ok(x) => { + let (section, validations) = x; + SectionValidation { + section, + validations: validations, + } + } + Err(x) => SectionValidation { + section: x, + validations: Validations::new(), + }, } } @@ -158,3 +175,53 @@ pub fn safe_parse_block(raw: String) -> Section { Err(x) => x, } } + +#[derive(Default, Debug)] +#[napi(object)] +pub struct Validation { + pub name: String, + pub value: bool, + pub description: String, +} + +impl Validation { + fn new() -> Self { + Default::default() + } + + pub fn with_description(self, description: impl ToString) -> Self { + Self { + description: description.to_string(), + ..self + } + } + + pub fn with_value(self, value: bool) -> Self { + Self { value, ..self } + } + + pub fn with_name(self, name: impl ToString) -> Self { + Self { + name: name.to_string(), + ..self + } + } +} + +#[derive(Debug, Default)] +#[napi(object)] +pub struct Validations { + pub validations: Vec, +} + +impl Validations { + pub fn new() -> Self { + Default::default() + } + + pub fn add_new_validation(mut self, validation: Validation) -> Self { + self.validations.push(validation); + + self + } +} diff --git a/napi-pallas/src/tx.rs b/napi-pallas/src/tx.rs index d293c4c..2be1295 100644 --- a/napi-pallas/src/tx.rs +++ b/napi-pallas/src/tx.rs @@ -1,3 +1,6 @@ +use crate::validations::validate::validate; +use crate::Validations; + use super::Section; use pallas::{ codec::utils::KeepRaw, @@ -5,7 +8,7 @@ use pallas::{ ledger::{ primitives::{ babbage::{Redeemer, RedeemerTag}, - conway::{Metadatum, PlutusData, PlutusV1Script, VKeyWitness}, + conway::{Metadatum, PlutusData, VKeyWitness}, ToCanonicalJson, }, traverse::{ComputeHash, MultiEraInput, MultiEraOutput, MultiEraTx}, @@ -98,8 +101,8 @@ fn print_metadatum(datum: &Metadatum) -> String { Metadatum::Int(x) => x.to_string(), Metadatum::Bytes(x) => hex::encode(x.as_slice()), Metadatum::Text(x) => x.to_owned(), - Metadatum::Array(x) => "[Array]".to_string(), - Metadatum::Map(x) => "[Map]".to_string(), + Metadatum::Array(_) => "[Array]".to_string(), + Metadatum::Map(_) => "[Map]".to_string(), } } @@ -190,7 +193,8 @@ fn tx_witnesses_section(tx: &MultiEraTx<'_>) -> Section { Section::new() .with_topic("tx_witnesses") .append_children(tx.vkey_witnesses().iter().map(tx_vkey_witnesses_section)) - .append_children(tx.redeemers().iter().map(tx_redeemer_section)) + // TODO: Uncomment when branch with this issue fixed is used + // .append_children(tx.redeemers().iter().map(tx_redeemer_section)) .append_children(tx.plutus_data().iter().map(tx_plutus_datum_section)) .append_children( tx.plutus_v1_scripts() @@ -209,11 +213,8 @@ fn tx_witnesses_section(tx: &MultiEraTx<'_>) -> Section { ) } -pub fn parse(raw: String) -> Result { +pub fn create_cbor_structure(tx: &MultiEraTx<'_>) -> Section { let out = Section::new().with_topic("cbor_parse").try_build_child(|| { - let cbor = hex::decode(raw)?; - let tx = MultiEraTx::decode(&cbor)?; - let child = Section::new() .with_topic("tx") .with_attr("era", tx.era()) @@ -231,6 +232,27 @@ pub fn parse(raw: String) -> Result { Ok(child) }); + out +} - Ok(out) +pub fn parse(raw: String) -> Result<(Section, Validations), Section> { + let res_cbor = hex::decode(raw); + match res_cbor { + Ok(cbor) => { + let res_mtx = MultiEraTx::decode(&cbor); + match res_mtx { + Ok(mtx) => Ok((create_cbor_structure(&mtx), validate(&mtx))), + Err(e) => { + let mut err = Section::new(); + err.error = Some(e.to_string()); + Err(err) + } + } + } + Err(e) => { + let mut err = Section::new(); + err.error = Some(e.to_string()); + Err(err) + } + } } diff --git a/napi-pallas/src/validations/alonzo.rs b/napi-pallas/src/validations/alonzo.rs new file mode 100644 index 0000000..8393406 --- /dev/null +++ b/napi-pallas/src/validations/alonzo.rs @@ -0,0 +1,8 @@ +use pallas::ledger::primitives::alonzo::MintedTx; + +use crate::Validations; + +pub fn validate_alonzo(mtx_a: &MintedTx) -> Validations { + let out = Validations::new(); + out +} diff --git a/napi-pallas/src/validations/babbage.rs b/napi-pallas/src/validations/babbage.rs new file mode 100644 index 0000000..8a8a6c6 --- /dev/null +++ b/napi-pallas/src/validations/babbage.rs @@ -0,0 +1,24 @@ +use crate::{Validation, Validations}; +use pallas::{ + applying::babbage::check_ins_not_empty, + ledger::primitives::babbage::{MintedTransactionBody, MintedTx as BabbageMintedTx}, +}; + +use super::validate::set_description; + +fn validate_babbage_ins_not_empty(mtx: &BabbageMintedTx) -> Validation { + let tx_body: &MintedTransactionBody = &mtx.transaction_body.clone(); + let res = check_ins_not_empty(tx_body); + let description = set_description(&res, "Inputs are not empty".to_string()); + return Validation::new() + .with_name("Non empty inputs".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +pub fn validate_babbage(mtx_b: &BabbageMintedTx) -> Validations { + let out = Validations::new() + .add_new_validation(validate_babbage_ins_not_empty(&mtx_b)) + .add_new_validation(validate_babbage_ins_not_empty(&mtx_b)); + out +} diff --git a/napi-pallas/src/validations/byron.rs b/napi-pallas/src/validations/byron.rs new file mode 100644 index 0000000..78cd641 --- /dev/null +++ b/napi-pallas/src/validations/byron.rs @@ -0,0 +1,6 @@ +use crate::Validations; +use pallas::ledger::primitives::byron::MintedTxPayload; +pub fn validate_byron(mtxp: &MintedTxPayload) -> Validations { + let out = Validations::new(); + out +} diff --git a/napi-pallas/src/validations/conway.rs b/napi-pallas/src/validations/conway.rs new file mode 100644 index 0000000..fa1ca30 --- /dev/null +++ b/napi-pallas/src/validations/conway.rs @@ -0,0 +1,7 @@ +use pallas::ledger::primitives::conway::MintedTx; + +use crate::Validations; +pub fn validate_conway(mtx_c: &MintedTx) -> Validations { + let out = Validations::new(); + out +} diff --git a/napi-pallas/src/validations/mod.rs b/napi-pallas/src/validations/mod.rs new file mode 100644 index 0000000..2b1fe12 --- /dev/null +++ b/napi-pallas/src/validations/mod.rs @@ -0,0 +1,6 @@ +pub mod alonzo; +pub mod babbage; +pub mod byron; +pub mod conway; +pub mod shelley_ma; +pub mod validate; diff --git a/napi-pallas/src/validations/shelley_ma.rs b/napi-pallas/src/validations/shelley_ma.rs new file mode 100644 index 0000000..3778f67 --- /dev/null +++ b/napi-pallas/src/validations/shelley_ma.rs @@ -0,0 +1,8 @@ +use pallas::ledger::primitives::alonzo::MintedTx; + +use crate::Validations; + +pub fn validate_shelley_ma(mtx_sma: &MintedTx) -> Validations { + let out = Validations::new(); + out +} diff --git a/napi-pallas/src/validations/validate.rs b/napi-pallas/src/validations/validate.rs new file mode 100644 index 0000000..8a43c6e --- /dev/null +++ b/napi-pallas/src/validations/validate.rs @@ -0,0 +1,31 @@ +use crate::validations::babbage::validate_babbage; +use crate::Validations; + +use pallas::applying::utils::ValidationError; +use pallas::ledger::traverse::{Era, MultiEraTx}; + +use super::alonzo::validate_alonzo; +use super::byron::validate_byron; +use super::conway::validate_conway; +use super::shelley_ma::validate_shelley_ma; + +pub fn set_description(res: &Result<(), ValidationError>, success: String) -> String { + match res { + Ok(_) => success, + Err(e) => format!("Error {:?}", e), + } +} + +pub fn validate(mtx: &MultiEraTx<'_>) -> Validations { + match &mtx { + MultiEraTx::Byron(mtxp) => validate_byron(&mtxp), + MultiEraTx::AlonzoCompatible(mtx_sma, Era::Shelley) + | MultiEraTx::AlonzoCompatible(mtx_sma, Era::Allegra) + | MultiEraTx::AlonzoCompatible(mtx_sma, Era::Mary) => validate_shelley_ma(&mtx_sma), + MultiEraTx::AlonzoCompatible(mtx_a, Era::Alonzo) => validate_alonzo(&mtx_a), + MultiEraTx::Babbage(mtx_b) => validate_babbage(&mtx_b), + MultiEraTx::Conway(mtx_c) => validate_conway(&mtx_c), + // This case is impossible. TODO: Handle error + _ => Validations::new(), + } +} diff --git a/web/app/routes/tx.server.ts b/web/app/routes/tx.server.ts index 361d020..947d774 100644 --- a/web/app/routes/tx.server.ts +++ b/web/app/routes/tx.server.ts @@ -1 +1 @@ -export { type Section, safeParseTx } from "napi-pallas"; +export { safeParseTx, type Section } from "napi-pallas"; diff --git a/web/yarn.lock b/web/yarn.lock index 1af6cae..3e5405f 100644 --- a/web/yarn.lock +++ b/web/yarn.lock @@ -33,7 +33,7 @@ resolved "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz" integrity sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw== -"@babel/core@^7.20.7", "@babel/core@^7.21.8": +"@babel/core@^7.0.0", "@babel/core@^7.0.0-0", "@babel/core@^7.20.7", "@babel/core@^7.21.8": version "7.23.7" resolved "https://registry.npmjs.org/@babel/core/-/core-7.23.7.tgz" integrity sha512-+UpDgowcmqe36d4NwqvKsyPMlOLNGMsfMmQ5WGCu+siCe3t3dfe9njrzGfdN4qq+bcNUt0+Vw6haRxBOycs4dw== @@ -319,226 +319,16 @@ resolved "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.1.tgz" integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ== -"@esbuild/android-arm64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.6.tgz#b11bd4e4d031bb320c93c83c137797b2be5b403b" - integrity sha512-YnYSCceN/dUzUr5kdtUzB+wZprCafuD89Hs0Aqv9QSdwhYQybhXTaSTcrl6X/aWThn1a/j0eEpUBGOE7269REg== - -"@esbuild/android-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.18.20.tgz#984b4f9c8d0377443cc2dfcef266d02244593622" - integrity sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ== - -"@esbuild/android-arm@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.6.tgz#ac6b5674da2149997f6306b3314dae59bbe0ac26" - integrity sha512-bSC9YVUjADDy1gae8RrioINU6e1lCkg3VGVwm0QQ2E1CWcC4gnMce9+B6RpxuSsrsXsk1yojn7sp1fnG8erE2g== - -"@esbuild/android-arm@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.18.20.tgz#fedb265bc3a589c84cc11f810804f234947c3682" - integrity sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw== - -"@esbuild/android-x64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.6.tgz#18c48bf949046638fc209409ff684c6bb35a5462" - integrity sha512-MVcYcgSO7pfu/x34uX9u2QIZHmXAB7dEiLQC5bBl5Ryqtpj9lT2sg3gNDEsrPEmimSJW2FXIaxqSQ501YLDsZQ== - -"@esbuild/android-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.18.20.tgz#35cf419c4cfc8babe8893d296cd990e9e9f756f2" - integrity sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg== - -"@esbuild/darwin-arm64@0.17.6": - version "0.17.6" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.6.tgz" - integrity sha512-bsDRvlbKMQMt6Wl08nHtFz++yoZHsyTOxnjfB2Q95gato+Yi4WnRl13oC2/PJJA9yLCoRv9gqT/EYX0/zDsyMA== - -"@esbuild/darwin-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.18.20.tgz" - integrity sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA== - -"@esbuild/darwin-x64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.6.tgz#f4dacd1ab21e17b355635c2bba6a31eba26ba569" - integrity sha512-xh2A5oPrYRfMFz74QXIQTQo8uA+hYzGWJFoeTE8EvoZGHb+idyV4ATaukaUvnnxJiauhs/fPx3vYhU4wiGfosg== - -"@esbuild/darwin-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.18.20.tgz#d70d5790d8bf475556b67d0f8b7c5bdff053d85d" - integrity sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ== - -"@esbuild/freebsd-arm64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.6.tgz#ea4531aeda70b17cbe0e77b0c5c36298053855b4" - integrity sha512-EnUwjRc1inT4ccZh4pB3v1cIhohE2S4YXlt1OvI7sw/+pD+dIE4smwekZlEPIwY6PhU6oDWwITrQQm5S2/iZgg== - -"@esbuild/freebsd-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.18.20.tgz#98755cd12707f93f210e2494d6a4b51b96977f54" - integrity sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw== - -"@esbuild/freebsd-x64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.6.tgz#1896170b3c9f63c5e08efdc1f8abc8b1ed7af29f" - integrity sha512-Uh3HLWGzH6FwpviUcLMKPCbZUAFzv67Wj5MTwK6jn89b576SR2IbEp+tqUHTr8DIl0iDmBAf51MVaP7pw6PY5Q== - -"@esbuild/freebsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.18.20.tgz#c1eb2bff03915f87c29cece4c1a7fa1f423b066e" - integrity sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ== - -"@esbuild/linux-arm64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.6.tgz#967dfb951c6b2de6f2af82e96e25d63747f75079" - integrity sha512-bUR58IFOMJX523aDVozswnlp5yry7+0cRLCXDsxnUeQYJik1DukMY+apBsLOZJblpH+K7ox7YrKrHmJoWqVR9w== - -"@esbuild/linux-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.18.20.tgz#bad4238bd8f4fc25b5a021280c770ab5fc3a02a0" - integrity sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA== - -"@esbuild/linux-arm@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.6.tgz#097a0ee2be39fed3f37ea0e587052961e3bcc110" - integrity sha512-7YdGiurNt7lqO0Bf/U9/arrPWPqdPqcV6JCZda4LZgEn+PTQ5SMEI4MGR52Bfn3+d6bNEGcWFzlIxiQdS48YUw== - -"@esbuild/linux-arm@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.18.20.tgz#3e617c61f33508a27150ee417543c8ab5acc73b0" - integrity sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg== - -"@esbuild/linux-ia32@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.6.tgz#a38a789d0ed157495a6b5b4469ec7868b59e5278" - integrity sha512-ujp8uoQCM9FRcbDfkqECoARsLnLfCUhKARTP56TFPog8ie9JG83D5GVKjQ6yVrEVdMie1djH86fm98eY3quQkQ== - -"@esbuild/linux-ia32@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.18.20.tgz#699391cccba9aee6019b7f9892eb99219f1570a7" - integrity sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA== - -"@esbuild/linux-loong64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.6.tgz#ae3983d0fb4057883c8246f57d2518c2af7cf2ad" - integrity sha512-y2NX1+X/Nt+izj9bLoiaYB9YXT/LoaQFYvCkVD77G/4F+/yuVXYCWz4SE9yr5CBMbOxOfBcy/xFL4LlOeNlzYQ== - -"@esbuild/linux-loong64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.18.20.tgz#e6fccb7aac178dd2ffb9860465ac89d7f23b977d" - integrity sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg== - -"@esbuild/linux-mips64el@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.6.tgz#15fbbe04648d944ec660ee5797febdf09a9bd6af" - integrity sha512-09AXKB1HDOzXD+j3FdXCiL/MWmZP0Ex9eR8DLMBVcHorrWJxWmY8Nms2Nm41iRM64WVx7bA/JVHMv081iP2kUA== - -"@esbuild/linux-mips64el@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.18.20.tgz#eeff3a937de9c2310de30622a957ad1bd9183231" - integrity sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ== - -"@esbuild/linux-ppc64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.6.tgz#38210094e8e1a971f2d1fd8e48462cc65f15ef19" - integrity sha512-AmLhMzkM8JuqTIOhxnX4ubh0XWJIznEynRnZAVdA2mMKE6FAfwT2TWKTwdqMG+qEaeyDPtfNoZRpJbD4ZBv0Tg== - -"@esbuild/linux-ppc64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.18.20.tgz#2f7156bde20b01527993e6881435ad79ba9599fb" - integrity sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA== - -"@esbuild/linux-riscv64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.6.tgz#bc3c66d5578c3b9951a6ed68763f2a6856827e4a" - integrity sha512-Y4Ri62PfavhLQhFbqucysHOmRamlTVK10zPWlqjNbj2XMea+BOs4w6ASKwQwAiqf9ZqcY9Ab7NOU4wIgpxwoSQ== - -"@esbuild/linux-riscv64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.18.20.tgz#6628389f210123d8b4743045af8caa7d4ddfc7a6" - integrity sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A== - -"@esbuild/linux-s390x@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.6.tgz#d7ba7af59285f63cfce6e5b7f82a946f3e6d67fc" - integrity sha512-SPUiz4fDbnNEm3JSdUW8pBJ/vkop3M1YwZAVwvdwlFLoJwKEZ9L98l3tzeyMzq27CyepDQ3Qgoba44StgbiN5Q== - -"@esbuild/linux-s390x@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.18.20.tgz#255e81fb289b101026131858ab99fba63dcf0071" - integrity sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ== - "@esbuild/linux-x64@0.17.6": version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.6.tgz#ba51f8760a9b9370a2530f98964be5f09d90fed0" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.6.tgz" integrity sha512-a3yHLmOodHrzuNgdpB7peFGPx1iJ2x6m+uDvhP2CKdr2CwOaqEFMeSqYAHU7hG+RjCq8r2NFujcd/YsEsFgTGw== "@esbuild/linux-x64@0.18.20": version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz#c7690b3417af318a9b6f96df3031a8865176d338" + resolved "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.18.20.tgz" integrity sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w== -"@esbuild/netbsd-x64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.6.tgz#e84d6b6fdde0261602c1e56edbb9e2cb07c211b9" - integrity sha512-EanJqcU/4uZIBreTrnbnre2DXgXSa+Gjap7ifRfllpmyAU7YMvaXmljdArptTHmjrkkKm9BK6GH5D5Yo+p6y5A== - -"@esbuild/netbsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.18.20.tgz#30e8cd8a3dded63975e2df2438ca109601ebe0d1" - integrity sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A== - -"@esbuild/openbsd-x64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.6.tgz#cf4b9fb80ce6d280a673d54a731d9c661f88b083" - integrity sha512-xaxeSunhQRsTNGFanoOkkLtnmMn5QbA0qBhNet/XLVsc+OVkpIWPHcr3zTW2gxVU5YOHFbIHR9ODuaUdNza2Vw== - -"@esbuild/openbsd-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.18.20.tgz#7812af31b205055874c8082ea9cf9ab0da6217ae" - integrity sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg== - -"@esbuild/sunos-x64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.6.tgz#a6838e246079b24d962b9dcb8d208a3785210a73" - integrity sha512-gnMnMPg5pfMkZvhHee21KbKdc6W3GR8/JuE0Da1kjwpK6oiFU3nqfHuVPgUX2rsOx9N2SadSQTIYV1CIjYG+xw== - -"@esbuild/sunos-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.18.20.tgz#d5c275c3b4e73c9b0ecd38d1ca62c020f887ab9d" - integrity sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ== - -"@esbuild/win32-arm64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.6.tgz#ace0186e904d109ea4123317a3ba35befe83ac21" - integrity sha512-G95n7vP1UnGJPsVdKXllAJPtqjMvFYbN20e8RK8LVLhlTiSOH1sd7+Gt7rm70xiG+I5tM58nYgwWrLs6I1jHqg== - -"@esbuild/win32-arm64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.18.20.tgz#73bc7f5a9f8a77805f357fab97f290d0e4820ac9" - integrity sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg== - -"@esbuild/win32-ia32@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.6.tgz#7fb3f6d4143e283a7f7dffc98a6baf31bb365c7e" - integrity sha512-96yEFzLhq5bv9jJo5JhTs1gI+1cKQ83cUpyxHuGqXVwQtY5Eq54ZEsKs8veKtiKwlrNimtckHEkj4mRh4pPjsg== - -"@esbuild/win32-ia32@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.18.20.tgz#ec93cbf0ef1085cc12e71e0d661d20569ff42102" - integrity sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g== - -"@esbuild/win32-x64@0.17.6": - version "0.17.6" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.6.tgz#563ff4277f1230a006472664fa9278a83dd124da" - integrity sha512-n6d8MOyUrNp6G4VSpRcgjs5xj4A91svJSaiwLIDWVWEsZtpN5FA9NlBbZHDmAJc2e8e6SF4tkBD3HAvPF+7igA== - -"@esbuild/win32-x64@0.18.20": - version "0.18.20" - resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.18.20.tgz#786c5f41f043b07afb1af37683d7c33668858f6d" - integrity sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ== - "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": version "4.4.0" resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" @@ -670,7 +460,7 @@ "@nodelib/fs.stat" "2.0.5" run-parallel "^1.1.9" -"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": version "2.0.5" resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== @@ -800,7 +590,7 @@ dependencies: "@remix-run/node" "2.5.0" -"@remix-run/node@2.5.0", "@remix-run/node@^2.5.0": +"@remix-run/node@^2.5.0", "@remix-run/node@2.5.0": version "2.5.0" resolved "https://registry.npmjs.org/@remix-run/node/-/node-2.5.0.tgz" integrity sha512-TTW4U+GnreqSf08Muz9jOJ5h5jPAPZ+UnwjLrq2O22dNyXrEzz2zecOddQ0H9Uk4ALS0HIu5206nK0pGW0Vdsg== @@ -963,7 +753,7 @@ resolved "https://registry.npmjs.org/@types/ms/-/ms-0.7.34.tgz" integrity sha512-nG96G3Wp6acyAgJqGasjODb+acrI7KltPiRxzHPXnP3NgI28bpQDRv53olbqGXbfcgF5aiiHmO3xpwEpS5Ld9g== -"@types/node@*": +"@types/node@*", "@types/node@>= 14": version "20.11.0" resolved "https://registry.npmjs.org/@types/node/-/node-20.11.0.tgz" integrity sha512-o9bjXmDNcF7GbM4CNQpmi+TutCgap/K3w1JyKgxAjqx41zp9qlIAVFi0IhCNsJcXolEqLWhbFbEeL0PvYm4pcQ== @@ -1023,6 +813,17 @@ semver "^7.5.4" ts-api-utils "^1.0.1" +"@typescript-eslint/parser@^6.0.0 || ^6.0.0-alpha": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz" + integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== + dependencies: + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + "@typescript-eslint/scope-manager@6.18.1": version "6.18.1" resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.18.1.tgz" @@ -1031,6 +832,14 @@ "@typescript-eslint/types" "6.18.1" "@typescript-eslint/visitor-keys" "6.18.1" +"@typescript-eslint/scope-manager@6.21.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz" + integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + "@typescript-eslint/type-utils@6.18.1": version "6.18.1" resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.18.1.tgz" @@ -1046,6 +855,11 @@ resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.18.1.tgz" integrity sha512-4TuMAe+tc5oA7wwfqMtB0Y5OrREPF1GeJBAjqwgZh1lEMH5PJQgWgHGfYufVB51LtjD+peZylmeyxUXPfENLCw== +"@typescript-eslint/types@6.21.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz" + integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== + "@typescript-eslint/typescript-estree@6.18.1": version "6.18.1" resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.18.1.tgz" @@ -1060,6 +874,20 @@ semver "^7.5.4" ts-api-utils "^1.0.1" +"@typescript-eslint/typescript-estree@6.21.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz" + integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + "@typescript-eslint/utils@6.18.1": version "6.18.1" resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.18.1.tgz" @@ -1081,6 +909,14 @@ "@typescript-eslint/types" "6.18.1" eslint-visitor-keys "^3.4.1" +"@typescript-eslint/visitor-keys@6.21.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz" + integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== + dependencies: + "@typescript-eslint/types" "6.21.0" + eslint-visitor-keys "^3.4.1" + "@ungap/structured-clone@^1.2.0": version "1.2.0" resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz" @@ -1164,7 +1000,7 @@ acorn-jsx@^5.0.0, acorn-jsx@^5.3.2: resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== -acorn@^8.0.0, acorn@^8.11.3, acorn@^8.9.0: +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@^8.0.0, acorn@^8.11.3, acorn@^8.9.0: version "8.11.3" resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== @@ -1447,7 +1283,7 @@ browserify-zlib@^0.1.4: dependencies: pako "~0.2.0" -browserslist@^4.22.2: +browserslist@^4.22.2, "browserslist@>= 4.21.0": version "4.22.2" resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.22.2.tgz" integrity sha512-0UgcrvQmBDvZHFGdYUehrCNIazki7/lUP3kkoi/r3YB2amZbFM9J43ZRkJTXBUZK4gmx56+Sqk9+Vs9mwZx9+A== @@ -1637,16 +1473,16 @@ color-convert@^2.0.1: dependencies: color-name "~1.1.4" -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - color-name@~1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + comma-separated-tokens@^2.0.0: version "2.0.3" resolved "https://registry.npmjs.org/comma-separated-tokens/-/comma-separated-tokens-2.0.3.tgz" @@ -1699,26 +1535,26 @@ convert-source-map@^2.0.0: resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz" integrity sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg== -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" - integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== - cookie-signature@^1.1.0: version "1.2.1" resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.2.1.tgz" integrity sha512-78KWk9T26NhzXtuL26cIJ8/qNHANyJ/ZYrmEXFzUmhZdjpBv+DlWlOANRTGBt48YcyslsLrj0bMLFTmXvLRCOw== -cookie@0.5.0: - version "0.5.0" - resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz" - integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz" + integrity sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ== cookie@^0.6.0: version "0.6.0" resolved "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz" integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== +cookie@0.5.0: + version "0.5.0" + resolved "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz" + integrity sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw== + core-util-is@~1.0.0: version "1.0.3" resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" @@ -1758,13 +1594,6 @@ data-uri-to-buffer@^3.0.1: resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-3.0.1.tgz" integrity sha512-WboRycPNsVw3B3TL559F7kuBUM4d8CgMEvk6xEJlOp7OBPjt6G7z8WMWlD2rOFZLk6OYfFIUGsCOWzcQH9K2og== -debug@2.6.9: - version "2.6.9" - resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - debug@^3.2.7: version "3.2.7" resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" @@ -1779,6 +1608,13 @@ debug@^4.0.0, debug@^4.1.0, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4: dependencies: ms "2.1.2" +debug@2.6.9: + version "2.6.9" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" + integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== + dependencies: + ms "2.0.0" + decode-named-character-reference@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/decode-named-character-reference/-/decode-named-character-reference-1.0.2.tgz" @@ -1826,7 +1662,7 @@ define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: has-property-descriptors "^1.0.0" object-keys "^1.1.1" -depd@2.0.0, depd@~2.0.0: +depd@~2.0.0, depd@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== @@ -2046,7 +1882,7 @@ esbuild-plugins-node-modules-polyfill@^1.6.0: local-pkg "^0.4.3" resolve.exports "^2.0.2" -esbuild@0.17.6: +"esbuild@^0.14.0 || ^0.15.0 || ^0.16.0 || ^0.17.0 || ^0.18.0 || ^0.19.0", esbuild@0.17.6: version "0.17.6" resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.17.6.tgz" integrity sha512-TKFRp9TxrJDdRWfSsSERKEovm6v30iHnrjlcGhLBOtReE28Yp1VSBRfO3GTaOFMoxsNerx4TjrhzSuma9ha83Q== @@ -2156,7 +1992,7 @@ eslint-module-utils@^2.7.4, eslint-module-utils@^2.8.0: dependencies: debug "^3.2.7" -eslint-plugin-import@^2.28.1: +eslint-plugin-import@*, eslint-plugin-import@^2.28.1: version "2.29.1" resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz" integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== @@ -2241,7 +2077,7 @@ eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4 resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -eslint@^8.38.0: +eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^3 || ^4 || ^5 || ^6 || ^7 || ^8", "eslint@^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", eslint@^8.38.0, eslint@>=7.0.0: version "8.56.0" resolved "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz" integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== @@ -2607,11 +2443,6 @@ fs.realpath@^1.0.0: resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - function-bind@^1.1.1, function-bind@^1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" @@ -2654,7 +2485,7 @@ get-intrinsic@^1.0.2, get-intrinsic@^1.1.1, get-intrinsic@^1.1.3, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" -get-port@5.1.1, get-port@^5.1.1: +get-port@^5.1.1, get-port@5.1.1: version "5.1.1" resolved "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz" integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== @@ -2919,7 +2750,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3: +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.3, inherits@2, inherits@2.0.4: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -3259,16 +3090,16 @@ js-yaml@^4.0.0, js-yaml@^4.1.0: dependencies: argparse "^2.0.1" -jsesc@3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz" - integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== - jsesc@^2.5.1: version "2.5.2" resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz" + integrity sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g== + json-buffer@3.0.1: version "3.0.1" resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" @@ -3443,7 +3274,17 @@ lru-cache@^6.0.0: dependencies: yallist "^4.0.0" -lru-cache@^7.4.4, lru-cache@^7.5.1, lru-cache@^7.7.1: +lru-cache@^7.4.4: + version "7.18.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + +lru-cache@^7.5.1: + version "7.18.3" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz" + integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== + +lru-cache@^7.7.1: version "7.18.3" resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz" integrity sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA== @@ -3926,7 +3767,7 @@ micromatch@^4.0.4, micromatch@^4.0.5: braces "^3.0.2" picomatch "^2.3.1" -mime-db@1.52.0, "mime-db@>= 1.43.0 < 2": +"mime-db@>= 1.43.0 < 2", mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== @@ -3948,20 +3789,34 @@ mimic-fn@^2.1.0: resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -minimatch@9.0.3, minimatch@^9.0.0, minimatch@^9.0.1: - version "9.0.3" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== +minimatch@^3.0.5: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: - brace-expansion "^2.0.1" + brace-expansion "^1.1.7" -minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: +minimatch@^3.1.1: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" +minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^9.0.0, minimatch@^9.0.1, minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + minimist@^1.2.0, minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" @@ -3995,16 +3850,16 @@ minipass@^3.0.0: dependencies: yallist "^4.0.0" -minipass@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" - integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== - "minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3: version "7.0.4" resolved "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz" integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ== +minipass@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz" + integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ== + minizlib@^2.1.1: version "2.1.2" resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" @@ -4059,17 +3914,17 @@ mrmime@^1.0.0: resolved "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz" integrity sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw== +ms@^2.1.1, ms@2.1.2: + version "2.1.2" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + ms@2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" integrity sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A== -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -ms@2.1.3, ms@^2.1.1: +ms@2.1.3: version "2.1.3" resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== @@ -4090,6 +3945,7 @@ nanoid@^3.3.7: napi-pallas@../napi-pallas: version "0.0.0" + resolved "file:../napi-pallas" natural-compare@^1.4.0: version "1.4.0" @@ -4235,13 +4091,6 @@ object.values@^1.1.6, object.values@^1.1.7: define-properties "^1.2.0" es-abstract "^1.22.1" -on-finished@2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" - integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== - dependencies: - ee-first "1.1.1" - on-finished@~2.3.0: version "2.3.0" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz" @@ -4249,6 +4098,13 @@ on-finished@~2.3.0: dependencies: ee-first "1.1.1" +on-finished@2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" + integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg== + dependencies: + ee-first "1.1.1" + on-headers@~1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz" @@ -4543,7 +4399,7 @@ postcss-value-parser@^4.0.0, postcss-value-parser@^4.1.0: resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz" integrity sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ== -postcss@^8.4.19, postcss@^8.4.23, postcss@^8.4.27: +postcss@^8.0.0, postcss@^8.1.0, postcss@^8.2.14, postcss@^8.2.15, postcss@^8.4.19, postcss@^8.4.21, postcss@^8.4.23, postcss@^8.4.27, postcss@>=8.0.9: version "8.4.33" resolved "https://registry.npmjs.org/postcss/-/postcss-8.4.33.tgz" integrity sha512-Kkpbhhdjw2qQs2O2DGX+8m5OVqEcbB9HRBvuYM9pgrjEFUg30A9LmXNlTAUj4S9kgtGyrMbTzVjH7E+s5Re2yg== @@ -4671,7 +4527,7 @@ raw-body@2.5.1: iconv-lite "0.4.24" unpipe "1.0.0" -react-dom@^18.2.0: +react-dom@^18.0.0, react-dom@^18.2.0, react-dom@>=16.8: version "18.2.0" resolved "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz" integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== @@ -4704,7 +4560,7 @@ react-router@6.21.2: dependencies: "@remix-run/router" "1.14.2" -react@^18.2.0: +react@^18.0.0, react@^18.2.0, react@>=16.8: version "18.2.0" resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== @@ -4718,7 +4574,7 @@ read-cache@^1.0.0: dependencies: pify "^2.3.0" -readable-stream@^2.0.0, readable-stream@~2.3.6: +readable-stream@^2.0.0: version "2.3.8" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== @@ -4740,6 +4596,19 @@ readable-stream@^3.1.1, readable-stream@^3.4.0: string_decoder "^1.1.1" util-deprecate "^1.0.1" +readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readdirp@~3.6.0: version "3.6.0" resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" @@ -4914,12 +4783,17 @@ safe-array-concat@^1.0.1: has-symbols "^1.0.3" isarray "^2.0.5" -safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@~5.1.0, safe-buffer@~5.1.1, safe-buffer@5.1.2: version "5.1.2" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== -safe-buffer@5.2.1, safe-buffer@~5.2.0: +safe-buffer@~5.2.0: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +safe-buffer@5.2.1: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== @@ -5064,7 +4938,12 @@ source-map-support@^0.5.21: buffer-from "^1.0.0" source-map "^0.6.0" -source-map@^0.6.0, source-map@^0.6.1: +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +source-map@^0.6.1: version "0.6.1" resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -5127,12 +5006,35 @@ stream-slice@^0.1.2: resolved "https://registry.npmjs.org/stream-slice/-/stream-slice-0.1.2.tgz" integrity sha512-QzQxpoacatkreL6jsxnVb7X5R/pGw9OUv2qWTYWnmLpg4NdN31snPy/f3TdQE1ZUXaThRvj1Zw4/OGg0ZkaLMA== +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + string-hash@^1.1.1: version "1.1.3" resolved "https://registry.npmjs.org/string-hash/-/string-hash-1.1.3.tgz" integrity sha512-kJUvRUFK49aub+a7T1nNE66EJbZBMnBgoC1UbCZ5n6bsZKBRga4KgBRTMn/pFkeCZSYtNeSyMxPDM0AXWELk2A== -"string-width-cjs@npm:string-width@^4.2.0", string-width@^4.1.0: +"string-width-cjs@npm:string-width@^4.2.0": + version "4.2.3" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +string-width@^4.1.0: version "4.2.3" resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== @@ -5192,20 +5094,6 @@ string.prototype.trimstart@^1.0.7: define-properties "^1.2.0" es-abstract "^1.22.1" -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - stringify-entities@^4.0.0: version "4.0.3" resolved "https://registry.npmjs.org/stringify-entities/-/stringify-entities-4.0.3.tgz" @@ -5214,7 +5102,14 @@ stringify-entities@^4.0.0: character-entities-html4 "^2.0.0" character-entities-legacy "^3.0.0" -"strip-ansi-cjs@npm:strip-ansi@^6.0.1", strip-ansi@^6.0.0, strip-ansi@^6.0.1: +"strip-ansi-cjs@npm:strip-ansi@^6.0.1": + version "6.0.1" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== @@ -5495,7 +5390,7 @@ typed-array-length@^1.0.4: for-each "^0.3.3" is-typed-array "^1.1.9" -typescript@^5.1.6: +typescript@^5.1.0, typescript@^5.1.6, typescript@>=4.2.0: version "5.3.3" resolved "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz" integrity sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw== @@ -5610,7 +5505,7 @@ universalify@^2.0.0: resolved "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz" integrity sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw== -unpipe@1.0.0, unpipe@~1.0.0: +unpipe@~1.0.0, unpipe@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== @@ -5713,7 +5608,7 @@ vite-node@^0.28.5: source-map-support "^0.5.21" vite "^3.0.0 || ^4.0.0" -"vite@^3.0.0 || ^4.0.0", vite@^4.1.4: +"vite@^3.0.0 || ^4.0.0", vite@^4.1.4, vite@^5.0.0: version "4.5.2" resolved "https://registry.npmjs.org/vite/-/vite-4.5.2.tgz" integrity sha512-tBCZBNSBbHQkaGyhGCDUGqeo2ph8Fstyp6FMSvTtsXeZSPpSMGlviAOav2hxVTqFcx8Hj/twtWKsMJXNY0xI8w== From cdd7ffacdadfa03d6d2508182cf69355557a7751 Mon Sep 17 00:00:00 2001 From: sara Date: Fri, 5 Apr 2024 16:24:29 -0300 Subject: [PATCH 04/16] feat: connection to front end --- napi-pallas/src/validations/babbage.rs | 4 +- web/app/components.tsx | 35 ++++++++--- web/app/routes/tx.tsx | 81 +++----------------------- 3 files changed, 37 insertions(+), 83 deletions(-) diff --git a/napi-pallas/src/validations/babbage.rs b/napi-pallas/src/validations/babbage.rs index 8a8a6c6..9006454 100644 --- a/napi-pallas/src/validations/babbage.rs +++ b/napi-pallas/src/validations/babbage.rs @@ -17,8 +17,6 @@ fn validate_babbage_ins_not_empty(mtx: &BabbageMintedTx) -> Validation { } pub fn validate_babbage(mtx_b: &BabbageMintedTx) -> Validations { - let out = Validations::new() - .add_new_validation(validate_babbage_ins_not_empty(&mtx_b)) - .add_new_validation(validate_babbage_ins_not_empty(&mtx_b)); + let out = Validations::new().add_new_validation(validate_babbage_ins_not_empty(&mtx_b)); out } diff --git a/web/app/components.tsx b/web/app/components.tsx index aad70cb..566e3af 100644 --- a/web/app/components.tsx +++ b/web/app/components.tsx @@ -53,18 +53,37 @@ export const P1 = Paragraph; export function RootSection(props: { data: Section; topics: Record; + validations: IValidation[]; }) { + const [open, setOpen] = useState(false); + const handleClick = () => setOpen(!open); const topic = getTopicMeta(props.data.topic, props.topics); + if (props.data.error) + return ( +
+

{topic.description}

+ {props.data.error} +
+ ); + return ( - <> +
+
+ + {open && } +

{topic.title}

- {!props.data.error && topic.description} - {!!props.data.error && ( -
- {props.data.error} -
- )} {!!props.data.bytes && ( )} @@ -74,7 +93,7 @@ export function RootSection(props: { {props.data.children?.map((c) => ( ))} - +
); } diff --git a/web/app/routes/tx.tsx b/web/app/routes/tx.tsx index bc4b149..f3b166a 100644 --- a/web/app/routes/tx.tsx +++ b/web/app/routes/tx.tsx @@ -1,12 +1,6 @@ import { ActionFunctionArgs, json, type MetaFunction } from "@remix-run/node"; import { Form, useActionData } from "@remix-run/react"; -import { useState } from "react"; -import { - Button, - logCuriosity, - RootSection, - ValidationAccordion, -} from "../components"; +import { Button, logCuriosity, RootSection } from "../components"; import * as server from "./tx.server"; import TOPICS from "./tx.topics"; @@ -32,8 +26,12 @@ export async function action({ request }: ActionFunctionArgs) { const raw = formData.get("raw"); if (raw) { - const res = server.safeParseTx(raw.toString()); - return json({ ...res, raw }); + const { section, validations } = server.safeParseTx(raw.toString()); + return json({ + ...section, + raw, + ...validations, + }); } else { return json({ error: "an empty value? seriously?" }); } @@ -59,54 +57,9 @@ function ExampleCard(props: { title: string; address: string }) { export default function Index() { const data = useActionData(); - const [open, setOpen] = useState(false); - const handleClick = () => setOpen(!open); - logCuriosity(data); - const validations: IValidation[] = [ - { name: "Non empty inputs", value: true, description: "Sucessful" }, - { - name: "All inputs in utxos", - value: false, - description: - "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", - }, - { name: "Validity interval", value: true, description: "Sucessful" }, - { name: "Fee", value: true, description: "Sucessful" }, - { - name: "Preservation of value", - value: false, - description: - "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", - }, - { - name: "Min lovelace per UTxO", - value: false, - description: - "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", - }, - { name: "Output value size", value: true, description: "Successful" }, - { name: "Network Id", value: true, description: "Successful" }, - { name: "Tx size", value: true, description: "Successful" }, - { name: "Tx execution units", value: true, description: "Successful" }, - { name: "Minting", value: true, description: "Successful" }, - { - name: "Well formed", - value: false, - description: - "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", - }, - { name: "Script witness", value: true, description: "Successful" }, - { name: "Languages", value: true, description: "Successful" }, - { - name: "Auxiliary data hash", - value: false, - description: - "Lorem ipsum dolor sit amet consectetur adipisicing elit. Porro id maiores exercitationem asperiores molestias assumenda doloremque magnam fugit. Iure dolorum fugit facilis autem incidunt vero necessitatibus consectetur ducimus recusandae blanditiis!", - }, - { name: "Script data hash", value: true, description: "Successful" }, - ]; + const validations: IValidation[] = data?.validations || []; return (
@@ -146,23 +99,7 @@ export default function Index() { )} {!!data && ( -
-
- - {open && } -
- -
+ )}
); From d44cd58d83e56d4521affb112494b5e6a4ce4b3c Mon Sep 17 00:00:00 2001 From: sara Date: Fri, 5 Apr 2024 16:34:36 -0300 Subject: [PATCH 05/16] feat: interfaces added --- web/app/components.tsx | 4 ++-- web/app/routes/tx.tsx | 9 +++++++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/web/app/components.tsx b/web/app/components.tsx index 566e3af..d305930 100644 --- a/web/app/components.tsx +++ b/web/app/components.tsx @@ -1,6 +1,6 @@ import { Attribute, type Section } from "napi-pallas"; import { PropsWithChildren, useState } from "react"; -import { IValidation } from "./routes/tx"; +import { DataProps, IValidation } from "./routes/tx"; export type TopicMeta = { title: string; @@ -178,7 +178,7 @@ export function TextArea(props: { name: string; placeholder?: string }) { ); } -export function logCuriosity(data: any) { +export function logCuriosity(data: DataProps) { if (data) { console.group("CURIOUS FELLOW, EH?"); console.log("hello there! want to learn how we parse the data?"); diff --git a/web/app/routes/tx.tsx b/web/app/routes/tx.tsx index f3b166a..f274231 100644 --- a/web/app/routes/tx.tsx +++ b/web/app/routes/tx.tsx @@ -14,6 +14,11 @@ export interface IValidations { validations: IValidation[]; } +export interface DataProps extends server.Section { + validations: IValidation[]; + raw?: string; +} + export const meta: MetaFunction = () => { return [ { title: "Cardano Tx - Lovelace Anatomy" }, @@ -55,9 +60,9 @@ function ExampleCard(props: { title: string; address: string }) { } export default function Index() { - const data = useActionData(); + const data: DataProps | undefined = useActionData(); - logCuriosity(data); + if (data) logCuriosity(data); const validations: IValidation[] = data?.validations || []; From 28d4a112628c94fda2801dd14bb5c99751925944 Mon Sep 17 00:00:00 2001 From: sara Date: Mon, 8 Apr 2024 16:03:12 -0300 Subject: [PATCH 06/16] feat: babbage validations added and era displayed on front --- napi-pallas/Cargo.toml | 2 +- napi-pallas/index.d.ts | 1 + napi-pallas/src/lib.rs | 8 + napi-pallas/src/validations/alonzo.rs | 2 +- napi-pallas/src/validations/babbage.rs | 309 +++++++++++++++++++++- napi-pallas/src/validations/byron.rs | 2 +- napi-pallas/src/validations/conway.rs | 2 +- napi-pallas/src/validations/shelley_ma.rs | 2 +- napi-pallas/src/validations/validate.rs | 2 +- web/app/components.tsx | 5 +- web/app/routes/tx.tsx | 10 +- 11 files changed, 334 insertions(+), 11 deletions(-) diff --git a/napi-pallas/Cargo.toml b/napi-pallas/Cargo.toml index cf2d72f..8b53243 100644 --- a/napi-pallas/Cargo.toml +++ b/napi-pallas/Cargo.toml @@ -12,7 +12,7 @@ hex = "0.4.3" # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix napi = { version = "2.12.2", default-features = false, features = ["napi4"] } napi-derive = "2.12.2" -pallas = { git = "https://github.com/alegadea/pallas.git", rev = "54ffc77" , features = ["unstable"]} +pallas = { git = "https://github.com/txpipe/pallas.git", rev = "2f97cbe" , features = ["unstable"]} [build-dependencies] napi-build = "2.0.1" diff --git a/napi-pallas/index.d.ts b/napi-pallas/index.d.ts index 7254742..21e5cf8 100644 --- a/napi-pallas/index.d.ts +++ b/napi-pallas/index.d.ts @@ -46,4 +46,5 @@ export interface Validation { } export interface Validations { validations: Array + era: string } diff --git a/napi-pallas/src/lib.rs b/napi-pallas/src/lib.rs index af1cc3a..5f175ff 100644 --- a/napi-pallas/src/lib.rs +++ b/napi-pallas/src/lib.rs @@ -212,6 +212,7 @@ impl Validation { #[napi(object)] pub struct Validations { pub validations: Vec, + pub era: String, } impl Validations { @@ -224,4 +225,11 @@ impl Validations { self } + + pub fn with_era(self, era: impl ToString) -> Self { + Self { + era: era.to_string(), + ..self + } + } } diff --git a/napi-pallas/src/validations/alonzo.rs b/napi-pallas/src/validations/alonzo.rs index 8393406..dace7cf 100644 --- a/napi-pallas/src/validations/alonzo.rs +++ b/napi-pallas/src/validations/alonzo.rs @@ -3,6 +3,6 @@ use pallas::ledger::primitives::alonzo::MintedTx; use crate::Validations; pub fn validate_alonzo(mtx_a: &MintedTx) -> Validations { - let out = Validations::new(); + let out = Validations::new().with_era("Alonzo".to_string()); out } diff --git a/napi-pallas/src/validations/babbage.rs b/napi-pallas/src/validations/babbage.rs index 9006454..cf44dae 100644 --- a/napi-pallas/src/validations/babbage.rs +++ b/napi-pallas/src/validations/babbage.rs @@ -1,22 +1,325 @@ use crate::{Validation, Validations}; use pallas::{ - applying::babbage::check_ins_not_empty, + applying::{ + babbage::{ + check_all_ins_in_utxos, check_auxiliary_data, check_fee, check_ins_not_empty, + check_languages, check_min_lovelace, check_minting, check_network_id, check_output_val_size, + check_preservation_of_value, check_script_data_hash, check_tx_ex_units, check_tx_size, + check_tx_validity_interval, check_well_formedness, check_witness_set, + }, + utils::{get_babbage_tx_size, BabbageProtParams, FeePolicy}, + Environment, MultiEraProtParams, UTxOs, + }, ledger::primitives::babbage::{MintedTransactionBody, MintedTx as BabbageMintedTx}, }; use super::validate::set_description; +// &The following validations only require the tx fn validate_babbage_ins_not_empty(mtx: &BabbageMintedTx) -> Validation { let tx_body: &MintedTransactionBody = &mtx.transaction_body.clone(); let res = check_ins_not_empty(tx_body); - let description = set_description(&res, "Inputs are not empty".to_string()); + let description = set_description( + &res, + "The set of transaction inputs is not empty.".to_string(), + ); return Validation::new() .with_name("Non empty inputs".to_string()) .with_value(res.is_ok()) .with_description(description); } +fn validate_babbage_minting(mtx: &BabbageMintedTx) -> Validation { + let tx_body: &MintedTransactionBody = &mtx.transaction_body.clone(); + let res = check_minting(tx_body, mtx); + let description = set_description( + &res, + "Each minted / burned asset is paired with an appropriate native script or Plutus script" + .to_string(), + ); + return Validation::new() + .with_name("Minting policy".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_babbage_well_formed(mtx: &BabbageMintedTx) -> Validation { + let tx_body: &MintedTransactionBody = &mtx.transaction_body.clone(); + let res = check_well_formedness(tx_body, mtx); + let description = set_description(&res, "The transaction is well-formed".to_string()); + return Validation::new() + .with_name("Well formedness".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_babbage_auxiliary_data(mtx: &BabbageMintedTx) -> Validation { + let tx_body = &mtx.transaction_body.clone(); + let res = check_auxiliary_data(tx_body, mtx); + let description = set_description( + &res, + "The metadata of the transaction is valid.".to_string(), + ); + return Validation::new() + .with_name("Auxiliary data".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// &The following validations also require the protocol parameters +fn validate_babbage_min_lovelace( + mtx: &BabbageMintedTx, + prot_pps: &BabbageProtParams, +) -> Validation { + let tx_body: &MintedTransactionBody = &mtx.transaction_body.clone(); + + let res = check_min_lovelace(tx_body, prot_pps); + let description = set_description( + &res, + "All transaction outputs (regular outputs and collateral outputs) contains at least the minimum lovelace.".to_string(), + ); + return Validation::new() + .with_name("Minimum lovelace".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_babbage_output_val_size( + mtx: &BabbageMintedTx, + prot_pps: &BabbageProtParams, +) -> Validation { + let tx_body: &MintedTransactionBody = &mtx.transaction_body.clone(); + let res = check_output_val_size(tx_body, prot_pps); + let description = set_description( + &res, + "The size of the value in each of the outputs is not greater than the maximum allowed." + .to_string(), + ); + return Validation::new() + .with_name("Output value size".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_babbage_tx_ex_units(mtx: &BabbageMintedTx, prot_pps: &BabbageProtParams) -> Validation { + let res = check_tx_ex_units(mtx, prot_pps); + let description = set_description( + &res, + "The number of execution units of the transaction does not exceed the maximum allowed." + .to_string(), + ); + return Validation::new() + .with_name("Transaction execution units".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// &The following validation also requires the tx size +fn validate_babbage_tx_size(size: &Option, prot_pps: &BabbageProtParams) -> Validation { + match size { + Some(size_value) => { + let res = check_tx_size(size_value, prot_pps); + let description = set_description( + &res, + "The size of the transaction does not exceed the maximum allowed.".to_string(), + ); + Validation::new() + .with_name("Transaction size".to_string()) + .with_value(res.is_ok()) + .with_description(description) + } + None => { + // Handle the case where size is None + // For example, return a specific validation result indicating that the size is not provided + Validation::new() + .with_name("Transaction size".to_string()) + .with_value(false) + .with_description("The transaction size could not be obtained.".to_string()) + } + } +} + +// &The following validation also requires the tx utxos +fn validate_babbage_fee( + mtx: &BabbageMintedTx, + size: &Option, + utxos: &UTxOs, + prot_pps: &BabbageProtParams, +) -> Validation { + match size { + Some(size_value) => { + let tx_body = &mtx.transaction_body.clone(); + let res = check_fee(tx_body, size_value, mtx, utxos, prot_pps); + let description = set_description(&res, "The fee of the transaction is valid.".to_string()); + return Validation::new() + .with_name("Fee".to_string()) + .with_value(res.is_ok()) + .with_description(description); + } + None => { + // Handle the case where size is None + // For example, return a specific validation result indicating that the size is not provided + Validation::new() + .with_name("Fee".to_string()) + .with_value(false) + .with_description("The transaction size could not be obtained.".to_string()) + } + } +} + +// &The following validations require the transaction and its utxos +fn validate_babbage_witness_set(mtx: &BabbageMintedTx, utxos: &UTxOs) -> Validation { + let res = check_witness_set(mtx, utxos); + let description = set_description( + &res, + "The witness set of the transaction is valid.".to_string(), + ); + return Validation::new() + .with_name("Witness set".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_babbage_all_ins_in_utxos(mtx: &BabbageMintedTx, utxos: &UTxOs) -> Validation { + let tx_body: &MintedTransactionBody = &mtx.transaction_body.clone(); + let res = check_all_ins_in_utxos(tx_body, utxos); + let description = set_description( + &res, + "All transaction inputs, collateral inputs and reference inputs are in the UTxO".to_string(), + ); + return Validation::new() + .with_name("All inputs in UTxOs".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_babbage_preservation_of_value(mtx: &BabbageMintedTx, utxos: &UTxOs) -> Validation { + let tx_body: &MintedTransactionBody = &mtx.transaction_body.clone(); + let res = check_preservation_of_value(tx_body, utxos); + let description = set_description( + &res, + "The preservation of value property holds.".to_string(), + ); + return Validation::new() + .with_name("Preservation of value".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// &The following validation also require the network and the block slot +fn validate_babbage_languages( + mtx: &BabbageMintedTx, + utxos: &UTxOs, + network_magic: &u32, + network_id: &u8, + block_slot: u64, +) -> Validation { + let res = check_languages(mtx, utxos, &network_magic, &network_id, &block_slot); + let description = set_description( + &res, + "The Plutus scripts and native scripts of the transaction are valid.".to_string(), + ); + return Validation::new() + .with_name("Languages".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_babbage_script_data_hash( + mtx: &BabbageMintedTx, + utxos: &UTxOs, + network_magic: &u32, + network_id: &u8, + block_slot: u64, +) -> Validation { + let tx_body = &mtx.transaction_body.clone(); + let res = check_script_data_hash( + tx_body, + mtx, + utxos, + &network_magic, + &network_id, + &block_slot, + ); + let description = set_description( + &res, + "The Plutus scripts and native scripts of the transaction are valid.".to_string(), + ); + return Validation::new() + .with_name("Languages".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// &The following validation requires the tx and the block slot +fn validate_babbage_tx_validity_interval(mtx: &BabbageMintedTx, block_slot: u64) -> Validation { + let tx_body: &MintedTransactionBody = &mtx.transaction_body.clone(); + let res = check_tx_validity_interval(tx_body, &block_slot); + let description = set_description( + &res, + "The block slot is contained in the transaction validity interval.".to_string(), + ); + return Validation::new() + .with_name("Validity interval".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// &The following validation requires the tx and its network id +fn validate_babbage_network_id(mtx: &BabbageMintedTx, network_id: u8) -> Validation { + let tx_body: &MintedTransactionBody = &mtx.transaction_body.clone(); + let res = check_network_id(tx_body, &network_id); + let description = set_description( + &res, + "The network ID of each regular output as well as that of the collateral output match the global network ID." + .to_string(), + ); + return Validation::new() + .with_name("Network id".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + pub fn validate_babbage(mtx_b: &BabbageMintedTx) -> Validations { - let out = Validations::new().add_new_validation(validate_babbage_ins_not_empty(&mtx_b)); + let tx_body: &MintedTransactionBody = &mtx_b.transaction_body.clone(); + let size: &Option = &get_babbage_tx_size(tx_body); + let prot_params = BabbageProtParams { + fee_policy: FeePolicy { + summand: 155381, + multiplier: 44, + }, + max_tx_size: 16384, + max_block_ex_mem: 62000000, + max_block_ex_steps: 20000000000, + max_tx_ex_mem: 14000000, + max_tx_ex_steps: 10000000000, + max_val_size: 5000, + collateral_percent: 150, + max_collateral_inputs: 3, + coins_per_utxo_word: 4310, + }; + + let env: Environment = Environment { + prot_params: MultiEraProtParams::Babbage(prot_params.clone()), + prot_magic: 764824073, // Mainnet. For preprod: 1. For preview: 2 + block_slot: 72316896, // TODO: Must be an input + network_id: 1, // Mainnet. For preprod: 0. For preview: 0 + }; + + let out = Validations::new() + .with_era("Babbage".to_string()) + .add_new_validation(validate_babbage_ins_not_empty(&mtx_b)) + .add_new_validation(validate_babbage_minting(&mtx_b)) + .add_new_validation(validate_babbage_well_formed(&mtx_b)) + .add_new_validation(validate_babbage_auxiliary_data(&mtx_b)) + .add_new_validation(validate_babbage_min_lovelace(&mtx_b, &prot_params)) + .add_new_validation(validate_babbage_output_val_size(&mtx_b, &prot_params)) + .add_new_validation(validate_babbage_tx_ex_units(&mtx_b, &prot_params)) + .add_new_validation(validate_babbage_tx_size(&size, &prot_params)) + .add_new_validation(validate_babbage_tx_validity_interval( + &mtx_b, + env.block_slot, + )) + .add_new_validation(validate_babbage_network_id(&mtx_b, env.network_id)); out } diff --git a/napi-pallas/src/validations/byron.rs b/napi-pallas/src/validations/byron.rs index 78cd641..d7bbe94 100644 --- a/napi-pallas/src/validations/byron.rs +++ b/napi-pallas/src/validations/byron.rs @@ -1,6 +1,6 @@ use crate::Validations; use pallas::ledger::primitives::byron::MintedTxPayload; pub fn validate_byron(mtxp: &MintedTxPayload) -> Validations { - let out = Validations::new(); + let out = Validations::new().with_era("Byron".to_string()); out } diff --git a/napi-pallas/src/validations/conway.rs b/napi-pallas/src/validations/conway.rs index fa1ca30..1a4a002 100644 --- a/napi-pallas/src/validations/conway.rs +++ b/napi-pallas/src/validations/conway.rs @@ -2,6 +2,6 @@ use pallas::ledger::primitives::conway::MintedTx; use crate::Validations; pub fn validate_conway(mtx_c: &MintedTx) -> Validations { - let out = Validations::new(); + let out = Validations::new().with_era("Conway".to_string()); out } diff --git a/napi-pallas/src/validations/shelley_ma.rs b/napi-pallas/src/validations/shelley_ma.rs index 3778f67..e8c134c 100644 --- a/napi-pallas/src/validations/shelley_ma.rs +++ b/napi-pallas/src/validations/shelley_ma.rs @@ -3,6 +3,6 @@ use pallas::ledger::primitives::alonzo::MintedTx; use crate::Validations; pub fn validate_shelley_ma(mtx_sma: &MintedTx) -> Validations { - let out = Validations::new(); + let out = Validations::new().with_era("Shelley Mary Allegra".to_string()); out } diff --git a/napi-pallas/src/validations/validate.rs b/napi-pallas/src/validations/validate.rs index 8a43c6e..9cfb99a 100644 --- a/napi-pallas/src/validations/validate.rs +++ b/napi-pallas/src/validations/validate.rs @@ -12,7 +12,7 @@ use super::shelley_ma::validate_shelley_ma; pub fn set_description(res: &Result<(), ValidationError>, success: String) -> String { match res { Ok(_) => success, - Err(e) => format!("Error {:?}", e), + Err(e) => format!("Error: {:?}", e), } } diff --git a/web/app/components.tsx b/web/app/components.tsx index d305930..cb73df9 100644 --- a/web/app/components.tsx +++ b/web/app/components.tsx @@ -54,6 +54,7 @@ export function RootSection(props: { data: Section; topics: Record; validations: IValidation[]; + era: string; }) { const [open, setOpen] = useState(false); const handleClick = () => setOpen(!open); @@ -79,7 +80,9 @@ export function RootSection(props: { > {open ? "▼" : "▶"} -

Tx Validations

+
+

Tx Validations - {props.era}

+
{open && } diff --git a/web/app/routes/tx.tsx b/web/app/routes/tx.tsx index f274231..c872628 100644 --- a/web/app/routes/tx.tsx +++ b/web/app/routes/tx.tsx @@ -12,10 +12,12 @@ export interface IValidation { export interface IValidations { validations: IValidation[]; + era: string; } export interface DataProps extends server.Section { validations: IValidation[]; + era: string; raw?: string; } @@ -65,6 +67,7 @@ export default function Index() { if (data) logCuriosity(data); const validations: IValidation[] = data?.validations || []; + const era = data?.era || ""; return (
@@ -104,7 +107,12 @@ export default function Index() { )} {!!data && ( - + )}
); From ce07c8c673fa811f50f1ed13b33dee0ab8a324c8 Mon Sep 17 00:00:00 2001 From: sara Date: Mon, 8 Apr 2024 17:15:59 -0300 Subject: [PATCH 07/16] feat: byron validations added --- napi-pallas/src/validations/byron.rs | 135 ++++++++++++++++++++++++++- 1 file changed, 132 insertions(+), 3 deletions(-) diff --git a/napi-pallas/src/validations/byron.rs b/napi-pallas/src/validations/byron.rs index d7bbe94..bc64a16 100644 --- a/napi-pallas/src/validations/byron.rs +++ b/napi-pallas/src/validations/byron.rs @@ -1,6 +1,135 @@ -use crate::Validations; -use pallas::ledger::primitives::byron::MintedTxPayload; +use crate::{Validation, Validations}; +use pallas::{ + applying::{ + byron::{ + check_fees, check_ins_in_utxos, check_ins_not_empty, check_outs_have_lovelace, + check_outs_not_empty, check_size, check_witnesses, + }, + utils::{ByronProtParams, FeePolicy}, + UTxOs, + }, + codec::minicbor::encode, + ledger::primitives::byron::{MintedTxPayload, Tx}, +}; + +use super::validate::set_description; + +fn get_tx_size(tx: &Tx) -> u64 { + let mut buff: Vec = Vec::new(); + if encode(tx, &mut buff).is_ok() { + return buff.len() as u64; + } else { + return 0; + } +} + +// & The following validation requires the size and the protocol parameters +fn validate_byron_size(size: &u64, prot_pps: &ByronProtParams) -> Validation { + let res = check_size(&size, &prot_pps); + let description = set_description( + &res, + "The transaction size does not exceed the protocol limit.".to_string(), + ); + return Validation::new() + .with_name("Transaction size".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction +fn validate_byron_ins_not_empty(tx: &Tx) -> Validation { + let res = check_ins_not_empty(tx); + let description = set_description( + &res, + "The set of transaction inputs is not empty.".to_string(), + ); + return Validation::new() + .with_name("Non empty inputs".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_byron_outs_not_empty(tx: &Tx) -> Validation { + let res = check_outs_not_empty(tx); + let description = set_description( + &res, + "The set of transaction outputs is not empty.".to_string(), + ); + return Validation::new() + .with_name("Non empty outputs".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_byron_outs_have_lovelace(tx: &Tx) -> Validation { + let res = check_outs_have_lovelace(tx); + let description = set_description( + &res, + "All transaction outputs contain non-null Lovelace values.".to_string(), + ); + return Validation::new() + .with_name("Outputs have lovelace".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction and the UTXOs +fn validate_byron_ins_in_utxos(tx: &Tx, utxos: &UTxOs) -> Validation { + let res = check_ins_in_utxos(tx, utxos); + let description = set_description( + &res, + "All transaction inputs are in the set of (yet) unspent transaction outputs.".to_string(), + ); + return Validation::new() + .with_name("Inputs in UTXOs".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction, the UTXOs and the protocol magic +fn validate_byron_witnesses(tx: &MintedTxPayload, utxos: &UTxOs, prot_magic: u32) -> Validation { + let res = check_witnesses(&tx, &utxos, &prot_magic); + let description = set_description(&res, "All transaction witnesses are valid.".to_string()); + return Validation::new() + .with_name("Witnesses".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction, the size, the UTXOs and the protocol parameters +fn validate_byron_fees( + tx: &Tx, + size: &u64, + utxos: &UTxOs, + prot_pps: &ByronProtParams, +) -> Validation { + let res = check_fees(&tx, &size, &utxos, &prot_pps); + let description = set_description( + &res, + "Fees are not less than what is determined by the protocol.".to_string(), + ); + return Validation::new() + .with_name("Fees".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + pub fn validate_byron(mtxp: &MintedTxPayload) -> Validations { - let out = Validations::new().with_era("Byron".to_string()); + let tx: &Tx = &mtxp.transaction; + let size: &u64 = &get_tx_size(&tx); + let prot_pps: ByronProtParams = ByronProtParams { + fee_policy: FeePolicy { + summand: 155381, + multiplier: 44, + }, + max_tx_size: 16384, + }; + + let out = Validations::new() + .with_era("Byron".to_string()) + .add_new_validation(validate_byron_size(&size, &prot_pps)) + .add_new_validation(validate_byron_ins_not_empty(&tx)) + .add_new_validation(validate_byron_outs_not_empty(&tx)) + .add_new_validation(validate_byron_outs_have_lovelace(&tx)); out } From 791446870749ebe193c3397f4ab23e6a01e97479 Mon Sep 17 00:00:00 2001 From: sara Date: Tue, 9 Apr 2024 14:40:31 -0300 Subject: [PATCH 08/16] fix: tx size validation handle and button fix --- napi-pallas/src/validations/byron.rs | 6 ++++ web/app/components.tsx | 43 ++++++++++++++++------------ 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/napi-pallas/src/validations/byron.rs b/napi-pallas/src/validations/byron.rs index bc64a16..1af97d9 100644 --- a/napi-pallas/src/validations/byron.rs +++ b/napi-pallas/src/validations/byron.rs @@ -25,6 +25,12 @@ fn get_tx_size(tx: &Tx) -> u64 { // & The following validation requires the size and the protocol parameters fn validate_byron_size(size: &u64, prot_pps: &ByronProtParams) -> Validation { + if size == &0 { + return Validation::new() + .with_name("Transaction size".to_string()) + .with_value(false) + .with_description("The transaction size could not be obtained.".to_string()); + } let res = check_size(&size, &prot_pps); let description = set_description( &res, diff --git a/web/app/components.tsx b/web/app/components.tsx index cb73df9..9ee674e 100644 --- a/web/app/components.tsx +++ b/web/app/components.tsx @@ -222,25 +222,32 @@ export function AccordionItem({ validation }: { validation: IValidation }) { onClick={handleClick} > {validation.value ? "✔" : "✘"}  {validation.name} - -
- + -
+ > + + + + -
- {open && ( -

{validation.description}

- )} +
+

{validation.description}

); @@ -250,7 +257,7 @@ export function ValidationAccordion(props: { validations: IValidation[] }) { return (
{props.validations.map((v) => ( From cb7e56130d3df0c16a221fc47dc2df531295ee0d Mon Sep 17 00:00:00 2001 From: sara Date: Tue, 9 Apr 2024 16:25:59 -0300 Subject: [PATCH 09/16] feat: validations for shelley era added --- napi-pallas/src/validations/shelley_ma.rs | 233 +++++++++++++++++++++- napi-pallas/src/validations/validate.rs | 10 +- 2 files changed, 236 insertions(+), 7 deletions(-) diff --git a/napi-pallas/src/validations/shelley_ma.rs b/napi-pallas/src/validations/shelley_ma.rs index e8c134c..9d15b6a 100644 --- a/napi-pallas/src/validations/shelley_ma.rs +++ b/napi-pallas/src/validations/shelley_ma.rs @@ -1,8 +1,233 @@ -use pallas::ledger::primitives::alonzo::MintedTx; +use pallas::{ + applying::{ + shelley_ma::{ + check_fees, check_ins_in_utxos, check_ins_not_empty, check_metadata, check_min_lovelace, + check_minting, check_network_id, check_preservation_of_value, check_ttl, check_tx_size, + check_witnesses, + }, + utils::{get_alonzo_comp_tx_size, FeePolicy, ShelleyProtParams}, + Environment, MultiEraProtParams, UTxOs, + }, + ledger::{ + primitives::alonzo::{MintedTx, MintedWitnessSet, TransactionBody}, + traverse::Era, + }, +}; -use crate::Validations; +use crate::{Validation, Validations}; -pub fn validate_shelley_ma(mtx_sma: &MintedTx) -> Validations { - let out = Validations::new().with_era("Shelley Mary Allegra".to_string()); +use super::validate::set_description; + +// & The following validation requires the size and the protocol parameters +fn validate_byron_ma_size(size: &Option, prot_pps: &ShelleyProtParams) -> Validation { + match size { + Some(size_value) => { + let res = check_tx_size(&size_value, &prot_pps); + let description = set_description( + &res, + "The transaction size does not exceed the protocol limit.".to_string(), + ); + return Validation::new() + .with_name("Transaction size".to_string()) + .with_value(res.is_ok()) + .with_description(description); + } + None => { + return Validation::new() + .with_name("Transaction size".to_string()) + .with_value(false) + .with_description("The transaction size could not be obtained.".to_string()); + } + } +} + +// & The following validations require the transaction +fn validate_shelley_ma_ins_not_empty(mtx_sma: &MintedTx) -> Validation { + let res = check_ins_not_empty(&mtx_sma.transaction_body); + let description = set_description( + &res, + "The set of transaction inputs is not empty.".to_string(), + ); + return Validation::new() + .with_name("Non empty inputs".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_shelley_ma_metadata(mtx_sma: &MintedTx) -> Validation { + let tx_body = &mtx_sma.transaction_body; + let res = check_metadata(&tx_body, mtx_sma); + let description = set_description( + &res, + "The metadata of the transaction is valid.".to_string(), + ); + return Validation::new() + .with_name("Metadata".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_shelley_ma_minting(mtx_sma: &MintedTx) -> Validation { + let tx_body = &mtx_sma.transaction_body; + let res = check_minting(&tx_body, mtx_sma); + let description = set_description(&res, "The minting of the transaction is valid.".to_string()); + return Validation::new() + .with_name("Minting".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction the protocol parameters +fn validate_shelley_ma_min_lovelace( + mtx_sma: &MintedTx, + prot_pps: &ShelleyProtParams, +) -> Validation { + let tx_body = &mtx_sma.transaction_body; + let res = check_min_lovelace(&tx_body, &prot_pps, &Era::Shelley); + let description = set_description( + &res, + "All transaction outputs contain Lovelace values not under the minimum.".to_string(), + ); + return Validation::new() + .with_name("Minimum lovelace".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction the size and the protocol parameters +fn validate_shelley_ma_fees( + mtx_sma: &MintedTx, + size: &Option, + prot_pps: &ShelleyProtParams, +) -> Validation { + match size { + Some(size_value) => { + let res = check_fees(&mtx_sma.transaction_body, &size_value, &prot_pps); + let description = set_description( + &res, + "The fee paid by the transaction has to be greater than or equal to the minimum fee." + .to_string(), + ); + return Validation::new() + .with_name("Fees".to_string()) + .with_value(res.is_ok()) + .with_description(description); + } + None => { + return Validation::new() + .with_name("Fees".to_string()) + .with_value(false) + .with_description("The transaction size could not be obtained.".to_string()); + } + } +} + +// & The following validations require the transaction and its utxos +fn validate_shelley_ma_ins_in_utxos(mtx_sma: &MintedTx, utxos: &UTxOs) -> Validation { + let tx_body = &mtx_sma.transaction_body; + let res = check_ins_in_utxos(tx_body, &utxos); + let description = set_description( + &res, + "All transaction inputs are in the set of (yet) unspent transaction outputs.".to_string(), + ); + return Validation::new() + .with_name("Inputs in UTxOs".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction its utxos and the era +fn validate_shelley_ma_preservation_of_value( + mtx_sma: &MintedTx, + utxos: &UTxOs, + era: &Era, +) -> Validation { + let tx_body = &mtx_sma.transaction_body; + let res = check_preservation_of_value(tx_body, &utxos, era); + let description = set_description( + &res, + "The preservation of value property holds.".to_string(), + ); + return Validation::new() + .with_name("Preservation of value".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction its witnesses set and its utxos +fn validate_shelley_ma_witnesses( + mtx_sma: &MintedTx, + tx_wits: &MintedWitnessSet, + utxos: &UTxOs, +) -> Validation { + let tx_body = &mtx_sma.transaction_body; + let res = check_witnesses(&tx_body, &tx_wits, &utxos); + let description = set_description( + &res, + " The owner of each transaction input signed the transaction.".to_string(), + ); + return Validation::new() + .with_name("Witnesses".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction and the block slot +fn validate_shelley_ma_ttl(mtx_sma: &MintedTx, block_slot: &u64) -> Validation { + let tx_body = &mtx_sma.transaction_body; + let res = check_ttl(&tx_body, &block_slot); + let description = set_description( + &res, + "The TTL limit of the transaction has not been exceeded.".to_string(), + ); + return Validation::new() + .with_name("TTL".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction and the network id +fn validate_shelley_ma_network_id(mtx_sma: &MintedTx, network_id: &u8) -> Validation { + let tx_body = &mtx_sma.transaction_body; + let res = check_network_id(&tx_body, &network_id); + let description = set_description( + &res, + "The network ID of each output matches the global network ID.".to_string(), + ); + return Validation::new() + .with_name("Network id".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +pub fn validate_shelley_ma(mtx_sma: &MintedTx, era: &Era) -> Validations { + let tx_body: &TransactionBody = &mtx_sma.transaction_body; + let tx_wits: &MintedWitnessSet = &mtx_sma.transaction_witness_set; + let size: &Option = &get_alonzo_comp_tx_size(tx_body); + let prot_params = ShelleyProtParams { + fee_policy: FeePolicy { + summand: 155381, + multiplier: 44, + }, + max_tx_size: 16384, + min_lovelace: 2000000, + }; + + let env: Environment = Environment { + prot_params: MultiEraProtParams::Shelley(prot_params.clone()), + prot_magic: 764824073, // Mainnet. For preprod: 1. For preview: 2 + block_slot: 72316896, // TODO: Must be an input + network_id: 1, // Mainnet. For preprod: 0. For preview: 0 + }; + let out = Validations::new() + .with_era("Shelley Mary Allegra".to_string()) + .add_new_validation(validate_byron_ma_size(&size, &prot_params)) + .add_new_validation(validate_shelley_ma_ins_not_empty(&mtx_sma)) + .add_new_validation(validate_shelley_ma_metadata(&mtx_sma)) + .add_new_validation(validate_shelley_ma_minting(&mtx_sma)) + .add_new_validation(validate_shelley_ma_min_lovelace(&mtx_sma, &prot_params)) + .add_new_validation(validate_shelley_ma_fees(&mtx_sma, &size, &prot_params)) + .add_new_validation(validate_shelley_ma_ttl(&mtx_sma, &env.block_slot)) + .add_new_validation(validate_shelley_ma_network_id(&mtx_sma, &env.network_id)); out } diff --git a/napi-pallas/src/validations/validate.rs b/napi-pallas/src/validations/validate.rs index 9cfb99a..4f1e583 100644 --- a/napi-pallas/src/validations/validate.rs +++ b/napi-pallas/src/validations/validate.rs @@ -19,9 +19,13 @@ pub fn set_description(res: &Result<(), ValidationError>, success: String) -> St pub fn validate(mtx: &MultiEraTx<'_>) -> Validations { match &mtx { MultiEraTx::Byron(mtxp) => validate_byron(&mtxp), - MultiEraTx::AlonzoCompatible(mtx_sma, Era::Shelley) - | MultiEraTx::AlonzoCompatible(mtx_sma, Era::Allegra) - | MultiEraTx::AlonzoCompatible(mtx_sma, Era::Mary) => validate_shelley_ma(&mtx_sma), + MultiEraTx::AlonzoCompatible(mtx_sma, Era::Shelley) => { + validate_shelley_ma(&mtx_sma, &Era::Shelley) + } + MultiEraTx::AlonzoCompatible(mtx_sma, Era::Allegra) => { + validate_shelley_ma(&mtx_sma, &Era::Allegra) + } + MultiEraTx::AlonzoCompatible(mtx_sma, Era::Mary) => validate_shelley_ma(&mtx_sma, &Era::Mary), MultiEraTx::AlonzoCompatible(mtx_a, Era::Alonzo) => validate_alonzo(&mtx_a), MultiEraTx::Babbage(mtx_b) => validate_babbage(&mtx_b), MultiEraTx::Conway(mtx_c) => validate_conway(&mtx_c), From 3c9c12f22357ce98f21798a6dc3354bf71995626 Mon Sep 17 00:00:00 2001 From: sara Date: Tue, 9 Apr 2024 17:34:23 -0300 Subject: [PATCH 10/16] feat: alonzo validations added --- napi-pallas/src/validations/alonzo.rs | 269 +++++++++++++++++++++++++- 1 file changed, 266 insertions(+), 3 deletions(-) diff --git a/napi-pallas/src/validations/alonzo.rs b/napi-pallas/src/validations/alonzo.rs index dace7cf..1496249 100644 --- a/napi-pallas/src/validations/alonzo.rs +++ b/napi-pallas/src/validations/alonzo.rs @@ -1,8 +1,271 @@ -use pallas::ledger::primitives::alonzo::MintedTx; +use pallas::{ + applying::{ + alonzo::{ + check_auxiliary_data, check_fee, check_ins_and_collateral_in_utxos, check_ins_not_empty, + check_languages, check_min_lovelace, check_minting, check_network_id, check_output_val_size, + check_preservation_of_value, check_script_data_hash, check_tx_ex_units, check_tx_size, + check_tx_validity_interval, check_witness_set, + }, + utils::{get_alonzo_comp_tx_size, AlonzoProtParams, FeePolicy}, + Environment, MultiEraProtParams, UTxOs, + }, + ledger::primitives::alonzo::{MintedTx, TransactionBody}, +}; -use crate::Validations; +use crate::{Validation, Validations}; + +use super::validate::set_description; + +// & The following validation requires the size and the protocol params +fn validate_alonzo_tx_size(size: &Option, prot_pps: &AlonzoProtParams) -> Validation { + match size { + Some(size_value) => { + let res = check_tx_size(&size_value, &prot_pps); + let description = set_description( + &res, + "The transaction size does not exceed the protocol limit.".to_string(), + ); + return Validation::new() + .with_name("Transaction size".to_string()) + .with_value(res.is_ok()) + .with_description(description); + } + None => { + return Validation::new() + .with_name("Transaction size".to_string()) + .with_value(false) + .with_description("The transaction size could not be obtained.".to_string()); + } + } +} + +// & The following validations require the transaction +fn validate_alonzo_ins_not_empty(mtx_a: &MintedTx) -> Validation { + let res = check_ins_not_empty(&mtx_a.transaction_body); + let description = set_description( + &res, + "The set of transaction inputs is not empty.".to_string(), + ); + return Validation::new() + .with_name("Non empty inputs".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_alonzo_auxiliary_data(mtx_a: &MintedTx) -> Validation { + let tx_body: &TransactionBody = &mtx_a.transaction_body; + let res = check_auxiliary_data(&tx_body, mtx_a); + let description = set_description( + &res, + "The auxiliary data of the transaction is valid.".to_string(), + ); + return Validation::new() + .with_name("Auxiliary data".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_alonzo_script_data_hash(mtx_a: &MintedTx) -> Validation { + let tx_body: &TransactionBody = &mtx_a.transaction_body; + let res = check_script_data_hash(&tx_body, mtx_a); + let description = set_description( + &res, + "The script data integrity hash matches the hash of the redeemers, languages and datums of the transaction witness set.".to_string(), + ); + return Validation::new() + .with_name("Script data hash".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_alonzo_minting(mtx_a: &MintedTx) -> Validation { + let tx_body: &TransactionBody = &mtx_a.transaction_body; + let res = check_minting(&tx_body, mtx_a); + let description = set_description( + &res, + "Each minted / burned asset is paired with an appropriate native script or Plutus script." + .to_string(), + ); + return Validation::new() + .with_name("Minting".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction and the protocol params +fn validate_alonzo_min_lovelace(mtx_a: &MintedTx, prot_pps: &AlonzoProtParams) -> Validation { + let tx_body: &TransactionBody = &mtx_a.transaction_body; + let res = check_min_lovelace(&tx_body, &prot_pps); + let description = set_description( + &res, + "All transaction outputs (regular outputs and collateral outputs) should contain at least the minimum lovelace".to_string(), + ); + return Validation::new() + .with_name("Minimum lovelace".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_alonzo_output_val_size(mtx_a: &MintedTx, prot_pps: &AlonzoProtParams) -> Validation { + let tx_body: &TransactionBody = &mtx_a.transaction_body; + let res = check_output_val_size(&tx_body, &prot_pps); + let description = set_description( + &res, + "The size of the value in each of the transaction outputs (regular outputs and collateral outputs) is not greater than the maximum allowed".to_string(), + ); + return Validation::new() + .with_name("Minimum lovelace".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_alonzo_tx_ex_units(mtx_a: &MintedTx, prot_pps: &AlonzoProtParams) -> Validation { + let res = check_tx_ex_units(mtx_a, &prot_pps); + let description = set_description( + &res, + "The size of the value in each of the transaction outputs (regular outputs and collateral outputs) is not greater than the maximum allowed".to_string(), + ); + return Validation::new() + .with_name("Minimum lovelace".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_alonzo_languages(mtx_a: &MintedTx, prot_pps: &AlonzoProtParams) -> Validation { + let res = check_languages(mtx_a, &prot_pps); + let description = set_description( + &res, + "The required script languages are included in the protocol parameters.".to_string(), + ); + return Validation::new() + .with_name("Minimum lovelace".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validation requires the transaction and the network id +fn validate_alonzo_network_id(mtx_a: &MintedTx, network_id: &u8) -> Validation { + let res = check_network_id(&mtx_a.transaction_body, network_id); + let description = set_description( + &res, + "The network ID of each output matches the global network ID.".to_string(), + ); + return Validation::new() + .with_name("Network ID".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction and the block slot +fn validate_alonzo_tx_validity_interval(mtx_a: &MintedTx, block_slot: &u64) -> Validation { + let res = check_tx_validity_interval(&mtx_a.transaction_body, mtx_a, block_slot); + let description = set_description( + &res, + "The upper bound of the validity time interval is suitable for script execution: if there are minting policies, native scripts or Plutus scripts involved in the transaction, and if the upper bound of its validity interval is a finite number, then it can be translated to system time.".to_string(), + ); + return Validation::new() + .with_name("Transaction validity interval".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validations require the transaction and its utxos +fn validate_alonzo_ins_and_collateral_in_utxos(mtx_a: &MintedTx, utxos: &UTxOs) -> Validation { + let res = check_ins_and_collateral_in_utxos(&mtx_a.transaction_body, utxos); + let description = set_description( + &res, + "All transaction inputs and collateral inputs are in the set of (yet) unspent transaction outputs.".to_string(), + ); + return Validation::new() + .with_name("Inputs and collateral in UTxOs".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_alonzo_preservation_of_value(mtx_a: &MintedTx, utxos: &UTxOs) -> Validation { + let res = check_preservation_of_value(&mtx_a.transaction_body, utxos); + let description = set_description( + &res, + "The preservation of value property holds.".to_string(), + ); + return Validation::new() + .with_name("Preservation of value".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +fn validate_alonzo_witness_set(mtx_a: &MintedTx, utxos: &UTxOs) -> Validation { + let res = check_witness_set(mtx_a, utxos); + let description = set_description(&res, "The transaction witness set is valid.".to_string()); + return Validation::new() + .with_name("Witness set".to_string()) + .with_value(res.is_ok()) + .with_description(description); +} + +// & The following validation requires the transaction, its utxos and the protocol params +fn validate_alonzo_fee(mtx_a: &MintedTx, utxos: &UTxOs, prot_pps: &AlonzoProtParams) -> Validation { + let tx_body: &TransactionBody = &mtx_a.transaction_body; + let size: &Option = &get_alonzo_comp_tx_size(tx_body); + match size { + Some(size_value) => { + let res = check_fee(tx_body, size_value, mtx_a, utxos, prot_pps); + let description = set_description( + &res, + "The fee paid by the transaction should be greater than or equal to the minimum fee." + .to_string(), + ); + return Validation::new() + .with_name("Fee".to_string()) + .with_value(res.is_ok()) + .with_description(description); + } + None => { + return Validation::new() + .with_name("Fee".to_string()) + .with_value(false) + .with_description("The size could not be obtained.".to_string()); + } + } +} pub fn validate_alonzo(mtx_a: &MintedTx) -> Validations { - let out = Validations::new().with_era("Alonzo".to_string()); + let tx_body: &TransactionBody = &mtx_a.transaction_body; + let size: &Option = &get_alonzo_comp_tx_size(tx_body); + let prot_params = AlonzoProtParams { + fee_policy: FeePolicy { + summand: 155381, + multiplier: 44, + }, + max_tx_size: 16384, + max_block_ex_mem: 62000000, + max_block_ex_steps: 20000000000, + max_tx_ex_mem: 14000000, + max_tx_ex_steps: 10000000000, + max_val_size: 5000, + collateral_percent: 150, + max_collateral_inputs: 3, + coins_per_utxo_word: 4310, + }; + + let env: Environment = Environment { + prot_params: MultiEraProtParams::Alonzo(prot_params.clone()), + prot_magic: 764824073, // Mainnet. For preprod: 1. For preview: 2 + block_slot: 72316896, // TODO: Must be an input + network_id: 1, // Mainnet. For preprod: 0. For preview: 0 + }; + let out = Validations::new() + .with_era("Alonzo".to_string()) + .add_new_validation(validate_alonzo_tx_size(size, &prot_params)) + .add_new_validation(validate_alonzo_ins_not_empty(mtx_a)) + .add_new_validation(validate_alonzo_auxiliary_data(mtx_a)) + .add_new_validation(validate_alonzo_script_data_hash(mtx_a)) + .add_new_validation(validate_alonzo_minting(mtx_a)) + .add_new_validation(validate_alonzo_min_lovelace(mtx_a, &prot_params)) + .add_new_validation(validate_alonzo_output_val_size(mtx_a, &prot_params)) + .add_new_validation(validate_alonzo_tx_ex_units(mtx_a, &prot_params)) + .add_new_validation(validate_alonzo_languages(mtx_a, &prot_params)) + .add_new_validation(validate_alonzo_network_id(mtx_a, &env.network_id)) + .add_new_validation(validate_alonzo_tx_validity_interval(mtx_a, &env.block_slot)); out } From c17c69ae1a3263622cc968a34a33f845d8c9d3e6 Mon Sep 17 00:00:00 2001 From: sara Date: Mon, 15 Apr 2024 16:15:45 -0300 Subject: [PATCH 11/16] feat: validations design and connection with napi validation calls --- napi-pallas/index.d.ts | 95 ++++++--- napi-pallas/src/lib.rs | 43 ++++- napi-pallas/src/tx.rs | 19 +- napi-pallas/src/validations/alonzo.rs | 44 +++-- napi-pallas/src/validations/babbage.rs | 46 +++-- napi-pallas/src/validations/byron.rs | 10 +- napi-pallas/src/validations/conway.rs | 8 +- napi-pallas/src/validations/shelley_ma.rs | 32 +++- napi-pallas/src/validations/validate.rs | 18 +- web/app/components.tsx | 223 +++++++++++++++++++++- web/app/interfaces.ts | 54 ++++++ web/app/routes/tx.tsx | 144 ++++++++++++-- web/public/settings.svg | 1 + 13 files changed, 618 insertions(+), 119 deletions(-) create mode 100644 web/app/interfaces.ts create mode 100644 web/public/settings.svg diff --git a/napi-pallas/index.d.ts b/napi-pallas/index.d.ts index 3bd279a..7fe8517 100644 --- a/napi-pallas/index.d.ts +++ b/napi-pallas/index.d.ts @@ -4,47 +4,82 @@ /* auto-generated by NAPI-RS */ export interface ShelleyPart { - isScript: boolean; - hash?: string; - pointer?: string; + isScript: boolean + hash?: string + pointer?: string } export interface AddressDiagnostic { - kind: string; - network?: string; - paymentPart?: ShelleyPart; - delegationPart?: ShelleyPart; - byronCbor?: string; + kind: string + network?: string + paymentPart?: ShelleyPart + delegationPart?: ShelleyPart + byronCbor?: string } export interface Output { - error?: string; - bytes?: string; - address?: AddressDiagnostic; + error?: string + bytes?: string + address?: AddressDiagnostic +} +export interface ValidationContext { + epoch: number + minFeeA: number + minFeeB: number + maxBlockSize: number + maxTxSize: number + maxBlockHeaderSize: number + keyDeposit: number + poolDeposit: number + eMax: number + nOpt: number + a0: number + rho: number + tau: number + decentralisationParam: number + extraEntropy: number + protocolMajorVer: number + protocolMinorVer: number + minUtxo: number + minPoolCost: number + priceMem: number + priceStep: number + maxTxExMem: number + maxTxExSteps: number + maxBlockExMem: number + maxBlockExSteps: number + maxValSize: number + collateralPercent: number + maxCollateralInputs: number + coinsPerUtxoSize: number + coinsPerUtxoWord: number + network: string + era: string + blockSlot: number } export interface Attribute { - topic?: string; - value?: string; + topic?: string + value?: string } export interface Section { - topic?: string; - identity?: string; - error?: string; - attributes: Array; - bytes?: string; - children: Array
; -} -export function parseAddress(raw: string): Output; + topic?: string + identity?: string + error?: string + attributes: Array + bytes?: string + children: Array
+} +export function parseAddress(raw: string): Output export interface SectionValidation { - section: Section; - validations: Validations; + section: Section + validations: Validations } -export function safeParseTx(raw: string): SectionValidation; -export function safeParseBlock(raw: string): Section; +export function safeParseTx(raw: string, context: ValidationContext): SectionValidation +export function safeParseBlock(raw: string): Section export interface Validation { - name: string; - value: boolean; - description: string; + name: string + value: boolean + description: string } export interface Validations { - validations: Array; - era: string; + validations: Array + era: string } diff --git a/napi-pallas/src/lib.rs b/napi-pallas/src/lib.rs index 5f175ff..a018745 100644 --- a/napi-pallas/src/lib.rs +++ b/napi-pallas/src/lib.rs @@ -10,6 +10,45 @@ mod block; mod tx; mod validations; +#[derive(Default)] +#[napi(object)] +pub struct ValidationContext { + pub epoch: i64, + pub min_fee_a: i64, + pub min_fee_b: i64, + pub max_block_size: i64, + pub max_tx_size: i64, + pub max_block_header_size: i64, + pub key_deposit: i64, + pub pool_deposit: i64, + pub e_max: i64, + pub n_opt: i64, + pub a0: i64, + pub rho: i64, + pub tau: i64, + pub decentralisation_param: i64, + pub extra_entropy: i64, + pub protocol_major_ver: i64, + pub protocol_minor_ver: i64, + pub min_utxo: i64, + pub min_pool_cost: i64, + pub price_mem: i64, + pub price_step: i64, + pub max_tx_ex_mem: u32, + pub max_tx_ex_steps: i64, + pub max_block_ex_mem: i64, + pub max_block_ex_steps: i64, + pub max_val_size: i64, + pub collateral_percent: i64, + pub max_collateral_inputs: i64, + pub coins_per_utxo_size: i64, + pub coins_per_utxo_word: i64, + + pub network: String, + pub era: String, + pub block_slot: i64, +} + #[derive(Default)] #[napi(object)] pub struct Attribute { @@ -152,8 +191,8 @@ pub struct SectionValidation { } #[napi] -pub fn safe_parse_tx(raw: String) -> SectionValidation { - match tx::parse(raw) { +pub fn safe_parse_tx(raw: String, context: ValidationContext) -> SectionValidation { + match tx::parse(raw, context) { Ok(x) => { let (section, validations) = x; SectionValidation { diff --git a/napi-pallas/src/tx.rs b/napi-pallas/src/tx.rs index 2be1295..950f830 100644 --- a/napi-pallas/src/tx.rs +++ b/napi-pallas/src/tx.rs @@ -1,7 +1,8 @@ -use crate::validations::validate::validate; use crate::Validations; +use crate::{validations::validate::validate, ValidationContext}; use super::Section; +use pallas::ledger::traverse::Era; use pallas::{ codec::utils::KeepRaw, crypto::hash::Hasher, @@ -235,13 +236,23 @@ pub fn create_cbor_structure(tx: &MultiEraTx<'_>) -> Section { out } -pub fn parse(raw: String) -> Result<(Section, Validations), Section> { +pub fn parse(raw: String, context: ValidationContext) -> Result<(Section, Validations), Section> { let res_cbor = hex::decode(raw); + let mut era_decode = Era::Babbage; + match context.era.as_str() { + "Alonzo" => era_decode = Era::Alonzo, + "Babbage" => era_decode = Era::Babbage, + "Byron" => era_decode = Era::Byron, + "Conway" => era_decode = Era::Conway, + "Shelley MA" => era_decode = Era::Shelley, + // This case should never happen + _ => {} + } match res_cbor { Ok(cbor) => { - let res_mtx = MultiEraTx::decode(&cbor); + let res_mtx = MultiEraTx::decode_for_era(era_decode, &cbor); match res_mtx { - Ok(mtx) => Ok((create_cbor_structure(&mtx), validate(&mtx))), + Ok(mtx) => Ok((create_cbor_structure(&mtx), validate(&mtx, context))), Err(e) => { let mut err = Section::new(); err.error = Some(e.to_string()); diff --git a/napi-pallas/src/validations/alonzo.rs b/napi-pallas/src/validations/alonzo.rs index 1496249..a6a7e79 100644 --- a/napi-pallas/src/validations/alonzo.rs +++ b/napi-pallas/src/validations/alonzo.rs @@ -12,7 +12,7 @@ use pallas::{ ledger::primitives::alonzo::{MintedTx, TransactionBody}, }; -use crate::{Validation, Validations}; +use crate::{Validation, ValidationContext, Validations}; use super::validate::set_description; @@ -229,30 +229,42 @@ fn validate_alonzo_fee(mtx_a: &MintedTx, utxos: &UTxOs, prot_pps: &AlonzoProtPar } } -pub fn validate_alonzo(mtx_a: &MintedTx) -> Validations { +pub fn validate_alonzo(mtx_a: &MintedTx, context: ValidationContext) -> Validations { let tx_body: &TransactionBody = &mtx_a.transaction_body; let size: &Option = &get_alonzo_comp_tx_size(tx_body); let prot_params = AlonzoProtParams { fee_policy: FeePolicy { - summand: 155381, - multiplier: 44, + summand: context.min_fee_b as u64, + multiplier: context.min_fee_a as u64, }, - max_tx_size: 16384, - max_block_ex_mem: 62000000, - max_block_ex_steps: 20000000000, - max_tx_ex_mem: 14000000, - max_tx_ex_steps: 10000000000, - max_val_size: 5000, - collateral_percent: 150, - max_collateral_inputs: 3, - coins_per_utxo_word: 4310, + max_tx_size: context.max_tx_size as u64, + max_block_ex_mem: context.max_block_ex_mem as u64, + max_block_ex_steps: context.max_block_ex_steps as u64, + max_tx_ex_mem: context.max_tx_ex_mem, + max_tx_ex_steps: context.max_tx_ex_steps as u64, + max_val_size: context.max_val_size as u64, + collateral_percent: context.collateral_percent as u64, + max_collateral_inputs: context.max_collateral_inputs as u64, + coins_per_utxo_word: context.coins_per_utxo_word as u64, }; + let mut magic = 764824073; // For mainnet + if context.network == "Preprod" { + magic = 1; + } else if context.network == "Preview" { + magic = 2; + } + + let mut net_id = 1; // For mainnet + if context.network == "Preprod" || context.network == "Preview" { + net_id = 0; + } + let env: Environment = Environment { prot_params: MultiEraProtParams::Alonzo(prot_params.clone()), - prot_magic: 764824073, // Mainnet. For preprod: 1. For preview: 2 - block_slot: 72316896, // TODO: Must be an input - network_id: 1, // Mainnet. For preprod: 0. For preview: 0 + prot_magic: magic, + block_slot: context.block_slot as u64, + network_id: net_id, }; let out = Validations::new() .with_era("Alonzo".to_string()) diff --git a/napi-pallas/src/validations/babbage.rs b/napi-pallas/src/validations/babbage.rs index cf44dae..4328816 100644 --- a/napi-pallas/src/validations/babbage.rs +++ b/napi-pallas/src/validations/babbage.rs @@ -1,4 +1,4 @@ -use crate::{Validation, Validations}; +use crate::{Validation, ValidationContext, Validations}; use pallas::{ applying::{ babbage::{ @@ -280,34 +280,46 @@ fn validate_babbage_network_id(mtx: &BabbageMintedTx, network_id: u8) -> Validat .with_description(description); } -pub fn validate_babbage(mtx_b: &BabbageMintedTx) -> Validations { +pub fn validate_babbage(mtx_b: &BabbageMintedTx, context: ValidationContext) -> Validations { let tx_body: &MintedTransactionBody = &mtx_b.transaction_body.clone(); let size: &Option = &get_babbage_tx_size(tx_body); let prot_params = BabbageProtParams { fee_policy: FeePolicy { - summand: 155381, - multiplier: 44, + summand: context.min_fee_b as u64, + multiplier: context.min_fee_a as u64, }, - max_tx_size: 16384, - max_block_ex_mem: 62000000, - max_block_ex_steps: 20000000000, - max_tx_ex_mem: 14000000, - max_tx_ex_steps: 10000000000, - max_val_size: 5000, - collateral_percent: 150, - max_collateral_inputs: 3, - coins_per_utxo_word: 4310, + max_tx_size: context.max_tx_size as u64, + max_block_ex_mem: context.max_block_ex_mem as u64, + max_block_ex_steps: context.max_block_ex_steps as u64, + max_tx_ex_mem: context.max_tx_ex_mem, + max_tx_ex_steps: context.max_tx_ex_steps as u64, + max_val_size: context.max_val_size as u64, + collateral_percent: context.collateral_percent as u64, + max_collateral_inputs: context.max_collateral_inputs as u64, + coins_per_utxo_word: context.coins_per_utxo_word as u64, }; + let mut magic = 764824073; // For mainnet + if context.network == "Preprod" { + magic = 1; + } else if context.network == "Preview" { + magic = 2; + } + + let mut net_id = 1; // For mainnet + if context.network == "Preprod" || context.network == "Preview" { + net_id = 0; + } + let env: Environment = Environment { prot_params: MultiEraProtParams::Babbage(prot_params.clone()), - prot_magic: 764824073, // Mainnet. For preprod: 1. For preview: 2 - block_slot: 72316896, // TODO: Must be an input - network_id: 1, // Mainnet. For preprod: 0. For preview: 0 + prot_magic: magic, + block_slot: context.block_slot as u64, + network_id: net_id, }; let out = Validations::new() - .with_era("Babbage".to_string()) + .with_era(context.era.to_string()) .add_new_validation(validate_babbage_ins_not_empty(&mtx_b)) .add_new_validation(validate_babbage_minting(&mtx_b)) .add_new_validation(validate_babbage_well_formed(&mtx_b)) diff --git a/napi-pallas/src/validations/byron.rs b/napi-pallas/src/validations/byron.rs index 1af97d9..47bb4be 100644 --- a/napi-pallas/src/validations/byron.rs +++ b/napi-pallas/src/validations/byron.rs @@ -1,4 +1,4 @@ -use crate::{Validation, Validations}; +use crate::{Validation, ValidationContext, Validations}; use pallas::{ applying::{ byron::{ @@ -120,15 +120,15 @@ fn validate_byron_fees( .with_description(description); } -pub fn validate_byron(mtxp: &MintedTxPayload) -> Validations { +pub fn validate_byron(mtxp: &MintedTxPayload, context: ValidationContext) -> Validations { let tx: &Tx = &mtxp.transaction; let size: &u64 = &get_tx_size(&tx); let prot_pps: ByronProtParams = ByronProtParams { fee_policy: FeePolicy { - summand: 155381, - multiplier: 44, + summand: context.min_fee_b as u64, + multiplier: context.min_fee_a as u64, }, - max_tx_size: 16384, + max_tx_size: context.max_tx_size as u64, }; let out = Validations::new() diff --git a/napi-pallas/src/validations/conway.rs b/napi-pallas/src/validations/conway.rs index 1a4a002..e92306d 100644 --- a/napi-pallas/src/validations/conway.rs +++ b/napi-pallas/src/validations/conway.rs @@ -2,6 +2,12 @@ use pallas::ledger::primitives::conway::MintedTx; use crate::Validations; pub fn validate_conway(mtx_c: &MintedTx) -> Validations { - let out = Validations::new().with_era("Conway".to_string()); + let out = Validations::new() + .with_era("Conway".to_string()) + .add_new_validation(crate::Validation { + name: "Coming soon...".to_string(), + value: true, + description: "Coming soon...".to_string(), + }); out } diff --git a/napi-pallas/src/validations/shelley_ma.rs b/napi-pallas/src/validations/shelley_ma.rs index 9d15b6a..37869bf 100644 --- a/napi-pallas/src/validations/shelley_ma.rs +++ b/napi-pallas/src/validations/shelley_ma.rs @@ -14,7 +14,7 @@ use pallas::{ }, }; -use crate::{Validation, Validations}; +use crate::{Validation, ValidationContext, Validations}; use super::validate::set_description; @@ -200,24 +200,40 @@ fn validate_shelley_ma_network_id(mtx_sma: &MintedTx, network_id: &u8) -> Valida .with_description(description); } -pub fn validate_shelley_ma(mtx_sma: &MintedTx, era: &Era) -> Validations { +pub fn validate_shelley_ma( + mtx_sma: &MintedTx, + era: &Era, + context: ValidationContext, +) -> Validations { let tx_body: &TransactionBody = &mtx_sma.transaction_body; let tx_wits: &MintedWitnessSet = &mtx_sma.transaction_witness_set; let size: &Option = &get_alonzo_comp_tx_size(tx_body); let prot_params = ShelleyProtParams { fee_policy: FeePolicy { - summand: 155381, - multiplier: 44, + summand: context.min_fee_b as u64, + multiplier: context.min_fee_a as u64, }, - max_tx_size: 16384, + max_tx_size: context.max_tx_size as u64, min_lovelace: 2000000, }; + let mut magic = 764824073; // For mainnet + if context.network == "Preprod" { + magic = 1; + } else if context.network == "Preview" { + magic = 2; + } + + let mut net_id = 1; // For mainnet + if context.network == "Preprod" || context.network == "Preview" { + net_id = 0; + } + let env: Environment = Environment { prot_params: MultiEraProtParams::Shelley(prot_params.clone()), - prot_magic: 764824073, // Mainnet. For preprod: 1. For preview: 2 - block_slot: 72316896, // TODO: Must be an input - network_id: 1, // Mainnet. For preprod: 0. For preview: 0 + prot_magic: magic, + block_slot: context.block_slot as u64, + network_id: net_id, }; let out = Validations::new() .with_era("Shelley Mary Allegra".to_string()) diff --git a/napi-pallas/src/validations/validate.rs b/napi-pallas/src/validations/validate.rs index 4f1e583..6212e18 100644 --- a/napi-pallas/src/validations/validate.rs +++ b/napi-pallas/src/validations/validate.rs @@ -1,5 +1,5 @@ use crate::validations::babbage::validate_babbage; -use crate::Validations; +use crate::{ValidationContext, Validations}; use pallas::applying::utils::ValidationError; use pallas::ledger::traverse::{Era, MultiEraTx}; @@ -16,18 +16,20 @@ pub fn set_description(res: &Result<(), ValidationError>, success: String) -> St } } -pub fn validate(mtx: &MultiEraTx<'_>) -> Validations { +pub fn validate(mtx: &MultiEraTx<'_>, context: ValidationContext) -> Validations { match &mtx { - MultiEraTx::Byron(mtxp) => validate_byron(&mtxp), + MultiEraTx::Byron(mtxp) => validate_byron(&mtxp, context), MultiEraTx::AlonzoCompatible(mtx_sma, Era::Shelley) => { - validate_shelley_ma(&mtx_sma, &Era::Shelley) + validate_shelley_ma(&mtx_sma, &Era::Shelley, context) } MultiEraTx::AlonzoCompatible(mtx_sma, Era::Allegra) => { - validate_shelley_ma(&mtx_sma, &Era::Allegra) + validate_shelley_ma(&mtx_sma, &Era::Allegra, context) } - MultiEraTx::AlonzoCompatible(mtx_sma, Era::Mary) => validate_shelley_ma(&mtx_sma, &Era::Mary), - MultiEraTx::AlonzoCompatible(mtx_a, Era::Alonzo) => validate_alonzo(&mtx_a), - MultiEraTx::Babbage(mtx_b) => validate_babbage(&mtx_b), + MultiEraTx::AlonzoCompatible(mtx_sma, Era::Mary) => { + validate_shelley_ma(&mtx_sma, &Era::Mary, context) + } + MultiEraTx::AlonzoCompatible(mtx_a, Era::Alonzo) => validate_alonzo(&mtx_a, context), + MultiEraTx::Babbage(mtx_b) => validate_babbage(&mtx_b, context), MultiEraTx::Conway(mtx_c) => validate_conway(&mtx_c), // This case is impossible. TODO: Handle error _ => Validations::new(), diff --git a/web/app/components.tsx b/web/app/components.tsx index 9ee674e..51e2f71 100644 --- a/web/app/components.tsx +++ b/web/app/components.tsx @@ -1,6 +1,14 @@ import { Attribute, type Section } from "napi-pallas"; -import { PropsWithChildren, useState } from "react"; -import { DataProps, IValidation } from "./routes/tx"; +import { PropsWithChildren, useEffect, useState } from "react"; +import { + DataProps, + EraType, + IContext, + IValidation, + NetworkType, + ProtocolType, + TabType, +} from "./interfaces"; export type TopicMeta = { title: string; @@ -212,14 +220,16 @@ export function AccordionItem({ validation }: { validation: IValidation }) { } `} > -
- -
+
+
); } + +export function ConfigsModal({ + closeModal, + protocolParams, + changeParam, + otherContext, + setOtherContext, +}: { + closeModal: () => void; + protocolParams: ProtocolType[]; + changeParam: ( + index: number + ) => (e: React.ChangeEvent) => void; + otherContext: IContext; + setOtherContext: (c: IContext) => void; +}) { + // To close config modal on esc press + useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if (event.key === "Escape") { + closeModal(); + } + }; + document.addEventListener("keydown", handleKeyDown); + + return () => { + document.removeEventListener("keydown", handleKeyDown); + }; + }, [closeModal]); + + return ( +
+
+
+
+

Tx Validation Configurations

+ + + +
+
+
+ ); +} + +function Tabs({ + otherContext, + protocolParams, + changeParam, + setOtherContext, +}: { + otherContext: IContext; + protocolParams: ProtocolType[]; + changeParam: ( + index: number + ) => (e: React.ChangeEvent) => void; + setOtherContext: (c: IContext) => void; +}) { + const tabs = ["Protocol Parameters", "Other Context"]; + const networks = ["Mainnet", "Preprod", "Preview"]; + const eras = ["Byron", "Shelley MA", "Alonzo", "Babbage", "Conway"]; + const [selected, setSelected] = useState("Protocol Parameters"); + + const changeSelected = (tab: TabType) => () => setSelected(tab); + const changeNetwork = (value: NetworkType) => () => + setOtherContext({ ...otherContext, selectedNetwork: value }); + const changeEra = (value: EraType) => () => + setOtherContext({ ...otherContext, selectedEra: value }); + const changeBlockSlot = (value: string) => { + setOtherContext({ ...otherContext, blockSlot: Number(value) }); + }; + + return ( +
+
+ {tabs.map((tab) => ( + + ))} +
+
+
+ {protocolParams.map((param, index) => ( +
+ + +
+ ))} +
+ +
+
+
Select a Network
+ {/* To get the network from the form*/} + +
+ {networks.map((net) => ( + + ))} +
+
+
+
Select an Era
+ {/* To get the era from the form*/} + +
+ {eras.map((era) => ( + + ))} +
+
+
+
Select a Block Slot
+ changeBlockSlot(e.target.value)} + className="block w-full px-4 py-2 mt-4 border-2 bg-white border-black h-16 shadow shadow-black rounded-lg rounded-b-xl border-b-8 appearance-none text-black placeholder-gray-400 text-2xl outline-none + focus:bg-pink-200" + /> +
+
+
+
+ ); +} diff --git a/web/app/interfaces.ts b/web/app/interfaces.ts new file mode 100644 index 0000000..e762030 --- /dev/null +++ b/web/app/interfaces.ts @@ -0,0 +1,54 @@ +import * as server from "./routes/tx.server"; + +export interface IValidation { + name: string; + value: boolean; + description: string; +} + +export interface IValidations { + validations: IValidation[]; + era: string; +} + +export interface DataProps extends server.Section { + validations: IValidation[]; + era: string; + raw?: string; +} + +export interface ProtocolType { + name: string; + value: number | null; +} + +export const TabType = { + ProtocolParameters: "Protocol Parameters", + Others: "Other Context", +} as const; + +export type TabType = (typeof TabType)[keyof typeof TabType]; + +export const NetworkType = { + Mainnet: "Mainnet", + Preprod: "Preprod", + Preview: "Preview", +} as const; + +export type NetworkType = (typeof NetworkType)[keyof typeof NetworkType]; + +export const Eras = { + Byron: "Byron", + ShelleyMA: "Shelley MA", + Alonzo: "Alonzo", + Babbage: "Babbage", + Conway: "Conway", +} as const; + +export type EraType = (typeof Eras)[keyof typeof Eras]; + +export interface IContext { + blockSlot: number; + selectedEra: EraType; + selectedNetwork: NetworkType; +} diff --git a/web/app/routes/tx.tsx b/web/app/routes/tx.tsx index 3d17edf..e933412 100644 --- a/web/app/routes/tx.tsx +++ b/web/app/routes/tx.tsx @@ -1,26 +1,12 @@ import { ActionFunctionArgs, json, type MetaFunction } from "@remix-run/node"; import { Form, useActionData } from "@remix-run/react"; -import { Button, RootSection, logCuriosity } from "../components"; +import { useState } from "react"; +import SettingsIcon from "../../public/settings.svg"; +import { Button, ConfigsModal, RootSection, logCuriosity } from "../components"; +import { DataProps, IContext, IValidation, ProtocolType } from "../interfaces"; import * as server from "./tx.server"; import TOPICS from "./tx.topics"; -export interface IValidation { - name: string; - value: boolean; - description: string; -} - -export interface IValidations { - validations: IValidation[]; - era: string; -} - -export interface DataProps extends server.Section { - validations: IValidation[]; - era: string; - raw?: string; -} - export const meta: MetaFunction = () => { return [ { title: "Cardano Tx - Lovelace Anatomy" }, @@ -31,9 +17,45 @@ export const meta: MetaFunction = () => { export async function action({ request }: ActionFunctionArgs) { const formData = await request.formData(); const raw = formData.get("raw"); + const era = formData.get("Era"); + const net = formData.get("Network"); if (raw) { - const { section, validations } = server.safeParseTx(raw.toString()); + const { section, validations } = server.safeParseTx(raw.toString(), { + epoch: Number(formData.get("Epoch")), + minFeeA: Number(formData.get("Min_fee_a")), + minFeeB: Number(formData.get("Min_fee_b")), + maxBlockSize: Number(formData.get("Max_block_size")), + maxTxSize: Number(formData.get("Max_tx_size")), + maxBlockHeaderSize: Number(formData.get("Max_block_header_size")), + keyDeposit: Number(formData.get("Key_deposit")), + poolDeposit: Number(formData.get("Pool_deposit")), + eMax: Number(formData.get("E_max")), + nOpt: Number(formData.get("N_opt")), + a0: Number(formData.get("A0")), + rho: Number(formData.get("Rho")), + tau: Number(formData.get("Tau")), + decentralisationParam: Number(formData.get("Decentralisation_param")), + extraEntropy: Number(formData.get("Extra_entropy")), + protocolMajorVer: Number(formData.get("Protocol_major_ver")), + protocolMinorVer: Number(formData.get("Protocol_minor_ver")), + minUtxo: Number(formData.get("Min_utxo")), + minPoolCost: Number(formData.get("Min_pool_cost")), + priceMem: Number(formData.get("Price_mem")), + priceStep: Number(formData.get("Price_step")), + maxTxExMem: Number(formData.get("Max_tx_ex_mem")), + maxTxExSteps: Number(formData.get("Max_tx_ex_steps")), + maxBlockExMem: Number(formData.get("Max_block_ex_mem")), + maxBlockExSteps: Number(formData.get("Max_block_ex_steps")), + maxValSize: Number(formData.get("Max_val_size")), + collateralPercent: Number(formData.get("Collateral_percent")), + maxCollateralInputs: Number(formData.get("Max_collateral_inputs")), + coinsPerUtxoSize: Number(formData.get("Coins_per_utxo_size")), + coinsPerUtxoWord: Number(formData.get("Coins_per_utxo_word")), + blockSlot: Number(formData.get("Block_slot")), + era: era?.toString() ?? "Babbage", + network: net?.toString() ?? "Mainnet", + }); return json({ ...section, raw, @@ -61,14 +83,73 @@ function ExampleCard(props: { title: string; address: string }) { ); } +const initialProtPps: ProtocolType[] = [ + { name: "Epoch", value: 478 }, + { name: "Min_fee_a", value: 44 }, + { name: "Min_fee_b", value: 155381 }, + { name: "Max_block_size", value: 90112 }, + { name: "Max_tx_size", value: 16384 }, + { name: "Max_block_header_size", value: 1100 }, + { name: "Key_deposit", value: 2000000 }, + { name: "Pool_deposit", value: 500000000 }, + { name: "E_max", value: 18 }, + { name: "N_opt", value: 500 }, + { name: "A0", value: 0.3 }, + { name: "Rho", value: 0.003 }, + { name: "Tau", value: 0.2 }, + { name: "Decentralisation_param", value: 0 }, + { name: "Extra_entropy", value: null }, + { name: "Protocol_major_ver", value: 8 }, + { name: "Protocol_minor_ver", value: 0 }, + { name: "Min_utxo", value: 4310 }, + { name: "Min_pool_cost", value: 170000000 }, + { name: "Price_mem", value: 0.0577 }, + { name: "Price_step", value: 0.0000721 }, + { name: "Max_tx_ex_mem", value: 14000000 }, + { name: "Max_tx_ex_steps", value: 10000000000 }, + { name: "Max_block_ex_mem", value: 62000000 }, + { name: "Max_block_ex_steps", value: 20000000000 }, + { name: "Max_val_size", value: 5000 }, + { name: "Collateral_percent", value: 150 }, + { name: "Max_collateral_inputs", value: 3 }, + { name: "Coins_per_utxo_size", value: 4310 }, + { name: "Coins_per_utxo_word", value: 4310 }, +]; + export default function Index() { const data: DataProps | undefined = useActionData(); + const [modalOpen, setModalOpen] = useState(false); + const [protocolParams, setProtocolParams] = + useState(initialProtPps); + + const [otherContext, setOtherContext] = useState({ + blockSlot: 72316896, + selectedEra: "Babbage", + selectedNetwork: "Mainnet", + }); if (data) logCuriosity(data); const validations: IValidation[] = data?.validations || []; const era = data?.era || ""; + const handleModal = () => setModalOpen((prev) => !prev); + + const changeParam = + (index: number) => (e: React.ChangeEvent) => { + setProtocolParams((prev: ProtocolType[]) => { + const updatedParams = [...prev]; + updatedParams[index] = { + ...updatedParams[index], + value: + Number(e.target.value) >= 0 + ? Number(e.target.value) + : updatedParams[index].value, + }; + return updatedParams; + }); + }; + return (

Cardano Tx

@@ -77,7 +158,12 @@ export default function Index() { inspect its contents.

-
+ { + setModalOpen(false); + }} + > -
+
+
+ {modalOpen && ( + + )}
diff --git a/web/public/settings.svg b/web/public/settings.svg new file mode 100644 index 0000000..269c81c --- /dev/null +++ b/web/public/settings.svg @@ -0,0 +1 @@ + \ No newline at end of file From e82e8e2cdb6b1f454ba9d3b5d014ebf2e6bea663 Mon Sep 17 00:00:00 2001 From: sara Date: Thu, 18 Apr 2024 16:00:46 -0300 Subject: [PATCH 12/16] feat: ppt params interfaces adapted to new updates in pallas --- napi-pallas/Cargo.toml | 2 +- napi-pallas/index.d.ts | 21 ++++-- napi-pallas/src/lib.rs | 45 ++++++----- napi-pallas/src/validations/alonzo.rs | 86 ++++++++++++++++----- napi-pallas/src/validations/babbage.rs | 92 ++++++++++++++++++----- napi-pallas/src/validations/byron.rs | 26 +++++-- napi-pallas/src/validations/shelley_ma.rs | 61 +++++++++++---- napi-pallas/src/validations/validate.rs | 2 +- web/app/components.tsx | 18 ++++- web/app/interfaces.ts | 2 +- web/app/routes/tx.tsx | 89 ++++++++++++---------- web/app/utils.ts | 71 +++++++++++++++++ 12 files changed, 380 insertions(+), 135 deletions(-) create mode 100644 web/app/utils.ts diff --git a/napi-pallas/Cargo.toml b/napi-pallas/Cargo.toml index 8b53243..3d38211 100644 --- a/napi-pallas/Cargo.toml +++ b/napi-pallas/Cargo.toml @@ -12,7 +12,7 @@ hex = "0.4.3" # Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix napi = { version = "2.12.2", default-features = false, features = ["napi4"] } napi-derive = "2.12.2" -pallas = { git = "https://github.com/txpipe/pallas.git", rev = "2f97cbe" , features = ["unstable"]} +pallas = { git = "https://github.com/txpipe/pallas.git", rev = "9f5713c" , features = ["unstable"]} [build-dependencies] napi-build = "2.0.1" diff --git a/napi-pallas/index.d.ts b/napi-pallas/index.d.ts index 7fe8517..947a5d1 100644 --- a/napi-pallas/index.d.ts +++ b/napi-pallas/index.d.ts @@ -31,17 +31,24 @@ export interface ValidationContext { poolDeposit: number eMax: number nOpt: number - a0: number - rho: number - tau: number - decentralisationParam: number - extraEntropy: number + a0Numerator: number + a0Denominator: number + rhoNumerator: number + rhoDenominator: number + tauNumerator: number + tauDenominator: number + decentralisationParamNumerator: number + decentralisationParamDenominator: number + extraEntropyNumerator: number + extraEntropyDenominator: number protocolMajorVer: number protocolMinorVer: number minUtxo: number minPoolCost: number - priceMem: number - priceStep: number + priceMemNumerator: number + priceMemDenominator: number + priceStepNumerator: number + priceStepDenominator: number maxTxExMem: number maxTxExSteps: number maxBlockExMem: number diff --git a/napi-pallas/src/lib.rs b/napi-pallas/src/lib.rs index a018745..09b7a8a 100644 --- a/napi-pallas/src/lib.rs +++ b/napi-pallas/src/lib.rs @@ -13,40 +13,47 @@ mod validations; #[derive(Default)] #[napi(object)] pub struct ValidationContext { - pub epoch: i64, - pub min_fee_a: i64, - pub min_fee_b: i64, - pub max_block_size: i64, - pub max_tx_size: i64, - pub max_block_header_size: i64, + pub epoch: u32, + pub min_fee_a: u32, + pub min_fee_b: u32, + pub max_block_size: u32, + pub max_tx_size: u32, + pub max_block_header_size: u32, pub key_deposit: i64, pub pool_deposit: i64, pub e_max: i64, - pub n_opt: i64, - pub a0: i64, - pub rho: i64, - pub tau: i64, - pub decentralisation_param: i64, - pub extra_entropy: i64, + pub n_opt: u32, + pub a0_numerator: i64, + pub a0_denominator: i64, + pub rho_numerator: i64, + pub rho_denominator: i64, + pub tau_numerator: i64, + pub tau_denominator: i64, + pub decentralisation_param_numerator: i64, + pub decentralisation_param_denominator: i64, + pub extra_entropy_numerator: u32, + pub extra_entropy_denominator: u32, pub protocol_major_ver: i64, pub protocol_minor_ver: i64, pub min_utxo: i64, pub min_pool_cost: i64, - pub price_mem: i64, - pub price_step: i64, + pub price_mem_numerator: i64, + pub price_mem_denominator: i64, + pub price_step_numerator: i64, + pub price_step_denominator: i64, pub max_tx_ex_mem: u32, pub max_tx_ex_steps: i64, - pub max_block_ex_mem: i64, + pub max_block_ex_mem: u32, pub max_block_ex_steps: i64, - pub max_val_size: i64, - pub collateral_percent: i64, - pub max_collateral_inputs: i64, + pub max_val_size: u32, + pub collateral_percent: u32, + pub max_collateral_inputs: u32, pub coins_per_utxo_size: i64, pub coins_per_utxo_word: i64, pub network: String, pub era: String, - pub block_slot: i64, + pub block_slot: u32, } #[derive(Default)] diff --git a/napi-pallas/src/validations/alonzo.rs b/napi-pallas/src/validations/alonzo.rs index a6a7e79..2fff5de 100644 --- a/napi-pallas/src/validations/alonzo.rs +++ b/napi-pallas/src/validations/alonzo.rs @@ -6,18 +6,22 @@ use pallas::{ check_preservation_of_value, check_script_data_hash, check_tx_ex_units, check_tx_size, check_tx_validity_interval, check_witness_set, }, - utils::{get_alonzo_comp_tx_size, AlonzoProtParams, FeePolicy}, - Environment, MultiEraProtParams, UTxOs, + utils::{get_alonzo_comp_tx_size, AlonzoProtParams}, + Environment, MultiEraProtocolParameters, UTxOs, + }, + ledger::primitives::{ + alonzo::{ExUnitPrices, Language, MintedTx, TransactionBody}, + conway::{ExUnits, Nonce, NonceVariant, RationalNumber}, }, - ledger::primitives::alonzo::{MintedTx, TransactionBody}, }; use crate::{Validation, ValidationContext, Validations}; use super::validate::set_description; +use pallas::codec::utils::KeyValuePairs; // & The following validation requires the size and the protocol params -fn validate_alonzo_tx_size(size: &Option, prot_pps: &AlonzoProtParams) -> Validation { +fn validate_alonzo_tx_size(size: &Option, prot_pps: &AlonzoProtParams) -> Validation { match size { Some(size_value) => { let res = check_tx_size(&size_value, &prot_pps); @@ -206,7 +210,7 @@ fn validate_alonzo_witness_set(mtx_a: &MintedTx, utxos: &UTxOs) -> Validation { // & The following validation requires the transaction, its utxos and the protocol params fn validate_alonzo_fee(mtx_a: &MintedTx, utxos: &UTxOs, prot_pps: &AlonzoProtParams) -> Validation { let tx_body: &TransactionBody = &mtx_a.transaction_body; - let size: &Option = &get_alonzo_comp_tx_size(tx_body); + let size: &Option = &get_alonzo_comp_tx_size(tx_body); match size { Some(size_value) => { let res = check_fee(tx_body, size_value, mtx_a, utxos, prot_pps); @@ -231,21 +235,65 @@ fn validate_alonzo_fee(mtx_a: &MintedTx, utxos: &UTxOs, prot_pps: &AlonzoProtPar pub fn validate_alonzo(mtx_a: &MintedTx, context: ValidationContext) -> Validations { let tx_body: &TransactionBody = &mtx_a.transaction_body; - let size: &Option = &get_alonzo_comp_tx_size(tx_body); + let size: &Option = &get_alonzo_comp_tx_size(tx_body); let prot_params = AlonzoProtParams { - fee_policy: FeePolicy { - summand: context.min_fee_b as u64, - multiplier: context.min_fee_a as u64, + minfee_a: context.min_fee_a, + minfee_b: context.min_fee_b, + max_block_body_size: context.max_block_size, + max_transaction_size: context.max_tx_size, + max_block_header_size: context.max_block_header_size, + key_deposit: context.key_deposit as u64, + pool_deposit: context.pool_deposit as u64, + maximum_epoch: context.e_max as u64, + desired_number_of_stake_pools: context.n_opt, + pool_pledge_influence: RationalNumber { + numerator: context.a0_numerator as u64, + denominator: context.a0_denominator as u64, + }, + expansion_rate: RationalNumber { + numerator: context.rho_numerator as u64, + denominator: context.rho_denominator as u64, + }, + treasury_growth_rate: RationalNumber { + numerator: context.tau_numerator as u64, + denominator: context.tau_denominator as u64, + }, + decentralization_constant: RationalNumber { + numerator: context.decentralisation_param_numerator as u64, + denominator: context.decentralisation_param_denominator as u64, + }, + extra_entropy: Nonce { + variant: NonceVariant::NeutralNonce, + hash: None, + }, + protocol_version: ( + context.protocol_minor_ver as u64, + context.protocol_major_ver as u64, + ), + min_pool_cost: context.min_pool_cost as u64, + cost_models_for_script_languages: KeyValuePairs::Def(vec![(Language::PlutusV1, vec![])]), + ada_per_utxo_byte: context.coins_per_utxo_size as u64, + execution_costs: ExUnitPrices { + mem_price: RationalNumber { + numerator: context.price_mem_numerator as u64, + denominator: context.price_mem_denominator as u64, + }, + step_price: RationalNumber { + numerator: context.price_step_numerator as u64, + denominator: context.price_step_denominator as u64, + }, + }, + max_tx_ex_units: ExUnits { + mem: context.max_tx_ex_mem, + steps: context.max_tx_ex_steps as u64, + }, + max_block_ex_units: ExUnits { + mem: context.max_block_ex_mem, + steps: context.max_block_ex_steps as u64, }, - max_tx_size: context.max_tx_size as u64, - max_block_ex_mem: context.max_block_ex_mem as u64, - max_block_ex_steps: context.max_block_ex_steps as u64, - max_tx_ex_mem: context.max_tx_ex_mem, - max_tx_ex_steps: context.max_tx_ex_steps as u64, - max_val_size: context.max_val_size as u64, - collateral_percent: context.collateral_percent as u64, - max_collateral_inputs: context.max_collateral_inputs as u64, - coins_per_utxo_word: context.coins_per_utxo_word as u64, + max_value_size: context.max_val_size, + collateral_percentage: context.collateral_percent, + max_collateral_inputs: context.max_collateral_inputs, }; let mut magic = 764824073; // For mainnet @@ -261,7 +309,7 @@ pub fn validate_alonzo(mtx_a: &MintedTx, context: ValidationContext) -> Validati } let env: Environment = Environment { - prot_params: MultiEraProtParams::Alonzo(prot_params.clone()), + prot_params: MultiEraProtocolParameters::Alonzo(prot_params.clone()), prot_magic: magic, block_slot: context.block_slot as u64, network_id: net_id, diff --git a/napi-pallas/src/validations/babbage.rs b/napi-pallas/src/validations/babbage.rs index 4328816..716fe86 100644 --- a/napi-pallas/src/validations/babbage.rs +++ b/napi-pallas/src/validations/babbage.rs @@ -7,10 +7,17 @@ use pallas::{ check_preservation_of_value, check_script_data_hash, check_tx_ex_units, check_tx_size, check_tx_validity_interval, check_well_formedness, check_witness_set, }, - utils::{get_babbage_tx_size, BabbageProtParams, FeePolicy}, - Environment, MultiEraProtParams, UTxOs, + utils::{get_babbage_tx_size, BabbageProtParams}, + Environment, MultiEraProtocolParameters, UTxOs, + }, + ledger::{ + primitives::{ + alonzo::ExUnitPrices, + babbage::{CostMdls, MintedTransactionBody, MintedTx as BabbageMintedTx}, + conway::{Nonce, NonceVariant, RationalNumber}, + }, + traverse::update::ExUnits, }, - ledger::primitives::babbage::{MintedTransactionBody, MintedTx as BabbageMintedTx}, }; use super::validate::set_description; @@ -115,7 +122,7 @@ fn validate_babbage_tx_ex_units(mtx: &BabbageMintedTx, prot_pps: &BabbageProtPar } // &The following validation also requires the tx size -fn validate_babbage_tx_size(size: &Option, prot_pps: &BabbageProtParams) -> Validation { +fn validate_babbage_tx_size(size: &Option, prot_pps: &BabbageProtParams) -> Validation { match size { Some(size_value) => { let res = check_tx_size(size_value, prot_pps); @@ -142,7 +149,7 @@ fn validate_babbage_tx_size(size: &Option, prot_pps: &BabbageProtParams) -> // &The following validation also requires the tx utxos fn validate_babbage_fee( mtx: &BabbageMintedTx, - size: &Option, + size: &Option, utxos: &UTxOs, prot_pps: &BabbageProtParams, ) -> Validation { @@ -282,21 +289,68 @@ fn validate_babbage_network_id(mtx: &BabbageMintedTx, network_id: u8) -> Validat pub fn validate_babbage(mtx_b: &BabbageMintedTx, context: ValidationContext) -> Validations { let tx_body: &MintedTransactionBody = &mtx_b.transaction_body.clone(); - let size: &Option = &get_babbage_tx_size(tx_body); + let size: &Option = &get_babbage_tx_size(tx_body); let prot_params = BabbageProtParams { - fee_policy: FeePolicy { - summand: context.min_fee_b as u64, - multiplier: context.min_fee_a as u64, + minfee_a: context.min_fee_a, + minfee_b: context.min_fee_b, + max_block_body_size: context.max_block_size, + max_transaction_size: context.max_tx_size, + max_block_header_size: context.max_block_header_size, + key_deposit: context.key_deposit as u64, + pool_deposit: context.pool_deposit as u64, + maximum_epoch: context.e_max as u64, + desired_number_of_stake_pools: context.n_opt, + pool_pledge_influence: RationalNumber { + numerator: context.a0_numerator as u64, + denominator: context.a0_denominator as u64, // ? + }, + expansion_rate: RationalNumber { + numerator: context.rho_numerator as u64, + denominator: context.rho_denominator as u64, // ? + }, + treasury_growth_rate: RationalNumber { + numerator: context.tau_numerator as u64, + denominator: context.tau_denominator as u64, // ? + }, + decentralization_constant: RationalNumber { + numerator: context.decentralisation_param_numerator as u64, + denominator: context.decentralisation_param_denominator as u64, // ? + }, + extra_entropy: Nonce { + variant: NonceVariant::NeutralNonce, + hash: None, + }, + protocol_version: ( + context.protocol_minor_ver as u64, + context.protocol_major_ver as u64, + ), + min_pool_cost: context.min_pool_cost as u64, + cost_models_for_script_languages: CostMdls { + plutus_v1: None, + plutus_v2: None, + }, + ada_per_utxo_byte: context.coins_per_utxo_size as u64, + execution_costs: ExUnitPrices { + mem_price: RationalNumber { + numerator: context.price_mem_numerator as u64, + denominator: context.price_mem_denominator as u64, // ? + }, + step_price: RationalNumber { + numerator: context.price_step_numerator as u64, + denominator: context.price_step_denominator as u64, // ? + }, + }, + max_tx_ex_units: ExUnits { + mem: context.max_tx_ex_mem, + steps: context.max_tx_ex_steps as u64, + }, + max_block_ex_units: ExUnits { + mem: context.max_block_ex_mem, + steps: context.max_block_ex_steps as u64, }, - max_tx_size: context.max_tx_size as u64, - max_block_ex_mem: context.max_block_ex_mem as u64, - max_block_ex_steps: context.max_block_ex_steps as u64, - max_tx_ex_mem: context.max_tx_ex_mem, - max_tx_ex_steps: context.max_tx_ex_steps as u64, - max_val_size: context.max_val_size as u64, - collateral_percent: context.collateral_percent as u64, - max_collateral_inputs: context.max_collateral_inputs as u64, - coins_per_utxo_word: context.coins_per_utxo_word as u64, + max_value_size: context.max_val_size, + collateral_percentage: context.collateral_percent, + max_collateral_inputs: context.max_collateral_inputs, }; let mut magic = 764824073; // For mainnet @@ -312,7 +366,7 @@ pub fn validate_babbage(mtx_b: &BabbageMintedTx, context: ValidationContext) -> } let env: Environment = Environment { - prot_params: MultiEraProtParams::Babbage(prot_params.clone()), + prot_params: MultiEraProtocolParameters::Babbage(prot_params.clone()), prot_magic: magic, block_slot: context.block_slot as u64, network_id: net_id, diff --git a/napi-pallas/src/validations/byron.rs b/napi-pallas/src/validations/byron.rs index 47bb4be..bee436d 100644 --- a/napi-pallas/src/validations/byron.rs +++ b/napi-pallas/src/validations/byron.rs @@ -1,11 +1,11 @@ -use crate::{Validation, ValidationContext, Validations}; +use crate::{Validation, Validations}; use pallas::{ applying::{ byron::{ check_fees, check_ins_in_utxos, check_ins_not_empty, check_outs_have_lovelace, check_outs_not_empty, check_size, check_witnesses, }, - utils::{ByronProtParams, FeePolicy}, + utils::ByronProtParams, UTxOs, }, codec::minicbor::encode, @@ -120,15 +120,25 @@ fn validate_byron_fees( .with_description(description); } -pub fn validate_byron(mtxp: &MintedTxPayload, context: ValidationContext) -> Validations { +pub fn validate_byron(mtxp: &MintedTxPayload) -> Validations { let tx: &Tx = &mtxp.transaction; let size: &u64 = &get_tx_size(&tx); let prot_pps: ByronProtParams = ByronProtParams { - fee_policy: FeePolicy { - summand: context.min_fee_b as u64, - multiplier: context.min_fee_a as u64, - }, - max_tx_size: context.max_tx_size as u64, + script_version: 0, + slot_duration: 20000, + max_block_size: 2000000, + max_header_size: 2000000, + max_tx_size: 4096, + max_proposal_size: 700, + mpc_thd: 20000000000000, + heavy_del_thd: 300000000000, + update_vote_thd: 1000000000000, + update_proposal_thd: 100000000000000, + update_implicit: 10000, + soft_fork_rule: (900000000000000, 600000000000000, 50000000000000), + summand: 155381, + multiplier: 44, + unlock_stake_epoch: 18446744073709551615, }; let out = Validations::new() diff --git a/napi-pallas/src/validations/shelley_ma.rs b/napi-pallas/src/validations/shelley_ma.rs index 37869bf..64bf861 100644 --- a/napi-pallas/src/validations/shelley_ma.rs +++ b/napi-pallas/src/validations/shelley_ma.rs @@ -5,12 +5,15 @@ use pallas::{ check_minting, check_network_id, check_preservation_of_value, check_ttl, check_tx_size, check_witnesses, }, - utils::{get_alonzo_comp_tx_size, FeePolicy, ShelleyProtParams}, - Environment, MultiEraProtParams, UTxOs, + utils::{get_alonzo_comp_tx_size, ShelleyProtParams}, + Environment, MultiEraProtocolParameters, UTxOs, }, ledger::{ - primitives::alonzo::{MintedTx, MintedWitnessSet, TransactionBody}, - traverse::Era, + primitives::{ + alonzo::{MintedTx, MintedWitnessSet, TransactionBody}, + conway::{NonceVariant, RationalNumber}, + }, + traverse::{update::Nonce, Era}, }, }; @@ -19,7 +22,7 @@ use crate::{Validation, ValidationContext, Validations}; use super::validate::set_description; // & The following validation requires the size and the protocol parameters -fn validate_byron_ma_size(size: &Option, prot_pps: &ShelleyProtParams) -> Validation { +fn validate_shelley_ma_tx_size(size: &Option, prot_pps: &ShelleyProtParams) -> Validation { match size { Some(size_value) => { let res = check_tx_size(&size_value, &prot_pps); @@ -83,7 +86,7 @@ fn validate_shelley_ma_min_lovelace( prot_pps: &ShelleyProtParams, ) -> Validation { let tx_body = &mtx_sma.transaction_body; - let res = check_min_lovelace(&tx_body, &prot_pps, &Era::Shelley); + let res = check_min_lovelace(&tx_body, &prot_pps); let description = set_description( &res, "All transaction outputs contain Lovelace values not under the minimum.".to_string(), @@ -97,7 +100,7 @@ fn validate_shelley_ma_min_lovelace( // & The following validations require the transaction the size and the protocol parameters fn validate_shelley_ma_fees( mtx_sma: &MintedTx, - size: &Option, + size: &Option, prot_pps: &ShelleyProtParams, ) -> Validation { match size { @@ -207,14 +210,42 @@ pub fn validate_shelley_ma( ) -> Validations { let tx_body: &TransactionBody = &mtx_sma.transaction_body; let tx_wits: &MintedWitnessSet = &mtx_sma.transaction_witness_set; - let size: &Option = &get_alonzo_comp_tx_size(tx_body); + let size: &Option = &get_alonzo_comp_tx_size(tx_body); let prot_params = ShelleyProtParams { - fee_policy: FeePolicy { - summand: context.min_fee_b as u64, - multiplier: context.min_fee_a as u64, + minfee_a: context.min_fee_a, + minfee_b: context.min_fee_b, + max_block_body_size: context.max_block_size, + max_transaction_size: context.max_tx_size, + max_block_header_size: context.max_block_header_size, + key_deposit: context.key_deposit as u64, + pool_deposit: context.pool_deposit as u64, + maximum_epoch: context.e_max as u64, + desired_number_of_stake_pools: context.n_opt, + pool_pledge_influence: RationalNumber { + numerator: context.a0_numerator as u64, + denominator: context.a0_denominator as u64, // ? + }, + expansion_rate: RationalNumber { + numerator: context.rho_numerator as u64, + denominator: context.rho_denominator as u64, // ? + }, + treasury_growth_rate: RationalNumber { + numerator: context.tau_numerator as u64, + denominator: context.tau_denominator as u64, // ? + }, + decentralization_constant: RationalNumber { + numerator: context.decentralisation_param_numerator as u64, + denominator: context.decentralisation_param_denominator as u64, // ? + }, + extra_entropy: Nonce { + variant: NonceVariant::NeutralNonce, + hash: None, }, - max_tx_size: context.max_tx_size as u64, - min_lovelace: 2000000, + protocol_version: ( + context.protocol_minor_ver as u64, + context.protocol_major_ver as u64, + ), + min_utxo_value: context.min_utxo as u64, }; let mut magic = 764824073; // For mainnet @@ -230,14 +261,14 @@ pub fn validate_shelley_ma( } let env: Environment = Environment { - prot_params: MultiEraProtParams::Shelley(prot_params.clone()), + prot_params: MultiEraProtocolParameters::Shelley(prot_params.clone()), prot_magic: magic, block_slot: context.block_slot as u64, network_id: net_id, }; let out = Validations::new() .with_era("Shelley Mary Allegra".to_string()) - .add_new_validation(validate_byron_ma_size(&size, &prot_params)) + .add_new_validation(validate_shelley_ma_tx_size(size, &prot_params)) .add_new_validation(validate_shelley_ma_ins_not_empty(&mtx_sma)) .add_new_validation(validate_shelley_ma_metadata(&mtx_sma)) .add_new_validation(validate_shelley_ma_minting(&mtx_sma)) diff --git a/napi-pallas/src/validations/validate.rs b/napi-pallas/src/validations/validate.rs index 6212e18..026e47d 100644 --- a/napi-pallas/src/validations/validate.rs +++ b/napi-pallas/src/validations/validate.rs @@ -18,7 +18,7 @@ pub fn set_description(res: &Result<(), ValidationError>, success: String) -> St pub fn validate(mtx: &MultiEraTx<'_>, context: ValidationContext) -> Validations { match &mtx { - MultiEraTx::Byron(mtxp) => validate_byron(&mtxp, context), + MultiEraTx::Byron(mtxp) => validate_byron(&mtxp), MultiEraTx::AlonzoCompatible(mtx_sma, Era::Shelley) => { validate_shelley_ma(&mtx_sma, &Era::Shelley, context) } diff --git a/web/app/components.tsx b/web/app/components.tsx index 51e2f71..bda7c9b 100644 --- a/web/app/components.tsx +++ b/web/app/components.tsx @@ -3,12 +3,14 @@ import { PropsWithChildren, useEffect, useState } from "react"; import { DataProps, EraType, + Eras, IContext, IValidation, NetworkType, ProtocolType, TabType, } from "./interfaces"; +import { ByronPptParams } from "./utils"; export type TopicMeta = { title: string; @@ -329,7 +331,7 @@ export function ConfigsModal({ hover:bg-info-400 hover:bg-pink-400 border-2 sm:w-auto rounded-lg py-2 tracking-wide w-full border-blue-950 shadow-black rounded-b-xl border-b-8 appearance-none text-black placeholder-gray-400 mt-3`} > - Submit + Submit & Dissect
@@ -364,6 +366,9 @@ function Tabs({ setOtherContext({ ...otherContext, blockSlot: Number(value) }); }; + const isByron = otherContext.selectedEra === Eras.Byron; + const paramsList = isByron ? ByronPptParams : protocolParams; + return (
@@ -386,7 +391,7 @@ function Tabs({ selected === TabType.ProtocolParameters ? "block" : "hidden" }`} > - {protocolParams.map((param, index) => ( + {paramsList.map((param, index) => (
))} diff --git a/web/app/interfaces.ts b/web/app/interfaces.ts index e762030..639f704 100644 --- a/web/app/interfaces.ts +++ b/web/app/interfaces.ts @@ -19,7 +19,7 @@ export interface DataProps extends server.Section { export interface ProtocolType { name: string; - value: number | null; + value: number; } export const TabType = { diff --git a/web/app/routes/tx.tsx b/web/app/routes/tx.tsx index e933412..a64646d 100644 --- a/web/app/routes/tx.tsx +++ b/web/app/routes/tx.tsx @@ -4,6 +4,7 @@ import { useState } from "react"; import SettingsIcon from "../../public/settings.svg"; import { Button, ConfigsModal, RootSection, logCuriosity } from "../components"; import { DataProps, IContext, IValidation, ProtocolType } from "../interfaces"; +import { decimalToFraction, initialProtPps } from "../utils"; import * as server from "./tx.server"; import TOPICS from "./tx.topics"; @@ -19,6 +20,26 @@ export async function action({ request }: ActionFunctionArgs) { const raw = formData.get("raw"); const era = formData.get("Era"); const net = formData.get("Network"); + const [a0Numerator, a0Denominator] = decimalToFraction( + Number(formData.get("A0")) + ); + const [rhoNumerator, rhoDenominator] = decimalToFraction( + Number(formData.get("Rho")) + ); + const [tauNumerator, tauDenominator] = decimalToFraction( + Number(formData.get("Tau")) + ); + const [decentralisationParamNumerator, decentralisationParamDenominator] = + decimalToFraction(Number(formData.get("Decentralisation_param"))); + const [extraEntropyNumerator, extraEntropyDenominator] = decimalToFraction( + Number(formData.get("Extra_entropy")) + ); + const [priceMemNumerator, priceMemDenominator] = decimalToFraction( + Number(formData.get("Price_mem")) + ); + const [priceStepNumerator, priceStepDenominator] = decimalToFraction( + Number(formData.get("Price_step")) + ); if (raw) { const { section, validations } = server.safeParseTx(raw.toString(), { @@ -32,17 +53,24 @@ export async function action({ request }: ActionFunctionArgs) { poolDeposit: Number(formData.get("Pool_deposit")), eMax: Number(formData.get("E_max")), nOpt: Number(formData.get("N_opt")), - a0: Number(formData.get("A0")), - rho: Number(formData.get("Rho")), - tau: Number(formData.get("Tau")), - decentralisationParam: Number(formData.get("Decentralisation_param")), - extraEntropy: Number(formData.get("Extra_entropy")), + a0Numerator: a0Numerator, + a0Denominator: a0Denominator, + rhoNumerator: rhoNumerator, + rhoDenominator: rhoDenominator, + tauNumerator: tauNumerator, + tauDenominator: tauDenominator, + decentralisationParamNumerator: decentralisationParamNumerator, + decentralisationParamDenominator: decentralisationParamDenominator, + extraEntropyNumerator: extraEntropyNumerator, + extraEntropyDenominator: extraEntropyDenominator, protocolMajorVer: Number(formData.get("Protocol_major_ver")), protocolMinorVer: Number(formData.get("Protocol_minor_ver")), minUtxo: Number(formData.get("Min_utxo")), minPoolCost: Number(formData.get("Min_pool_cost")), - priceMem: Number(formData.get("Price_mem")), - priceStep: Number(formData.get("Price_step")), + priceMemNumerator: priceMemNumerator, + priceMemDenominator: priceMemDenominator, + priceStepNumerator: priceStepNumerator, + priceStepDenominator: priceStepDenominator, maxTxExMem: Number(formData.get("Max_tx_ex_mem")), maxTxExSteps: Number(formData.get("Max_tx_ex_steps")), maxBlockExMem: Number(formData.get("Max_block_ex_mem")), @@ -74,7 +102,19 @@ function ExampleCard(props: { title: string; address: string }) { className="border-2 rounded-lg p-4 shadow bg-gray-100 cursor-pointer flex flex-col w-full h-full text-left" >

{props.title}

- + + + + + {initialProtPps.map((param) => ( + + ))} {props.address.substring(0, 30)}... @@ -83,39 +123,6 @@ function ExampleCard(props: { title: string; address: string }) { ); } -const initialProtPps: ProtocolType[] = [ - { name: "Epoch", value: 478 }, - { name: "Min_fee_a", value: 44 }, - { name: "Min_fee_b", value: 155381 }, - { name: "Max_block_size", value: 90112 }, - { name: "Max_tx_size", value: 16384 }, - { name: "Max_block_header_size", value: 1100 }, - { name: "Key_deposit", value: 2000000 }, - { name: "Pool_deposit", value: 500000000 }, - { name: "E_max", value: 18 }, - { name: "N_opt", value: 500 }, - { name: "A0", value: 0.3 }, - { name: "Rho", value: 0.003 }, - { name: "Tau", value: 0.2 }, - { name: "Decentralisation_param", value: 0 }, - { name: "Extra_entropy", value: null }, - { name: "Protocol_major_ver", value: 8 }, - { name: "Protocol_minor_ver", value: 0 }, - { name: "Min_utxo", value: 4310 }, - { name: "Min_pool_cost", value: 170000000 }, - { name: "Price_mem", value: 0.0577 }, - { name: "Price_step", value: 0.0000721 }, - { name: "Max_tx_ex_mem", value: 14000000 }, - { name: "Max_tx_ex_steps", value: 10000000000 }, - { name: "Max_block_ex_mem", value: 62000000 }, - { name: "Max_block_ex_steps", value: 20000000000 }, - { name: "Max_val_size", value: 5000 }, - { name: "Collateral_percent", value: 150 }, - { name: "Max_collateral_inputs", value: 3 }, - { name: "Coins_per_utxo_size", value: 4310 }, - { name: "Coins_per_utxo_word", value: 4310 }, -]; - export default function Index() { const data: DataProps | undefined = useActionData(); const [modalOpen, setModalOpen] = useState(false); diff --git a/web/app/utils.ts b/web/app/utils.ts new file mode 100644 index 0000000..c52c8fd --- /dev/null +++ b/web/app/utils.ts @@ -0,0 +1,71 @@ +import { ProtocolType } from "./interfaces"; + +export const initialProtPps: ProtocolType[] = [ + { name: "Epoch", value: 478 }, + { name: "Min_fee_a", value: 44 }, + { name: "Min_fee_b", value: 155381 }, + { name: "Max_block_size", value: 90112 }, + { name: "Max_tx_size", value: 16384 }, + { name: "Max_block_header_size", value: 1100 }, + { name: "Key_deposit", value: 2000000 }, + { name: "Pool_deposit", value: 500000000 }, + { name: "E_max", value: 18 }, + { name: "N_opt", value: 500 }, + { name: "A0", value: 0.3 }, + { name: "Rho", value: 0.003 }, + { name: "Tau", value: 0.2 }, + { name: "Decentralisation_param", value: 0 }, + { name: "Extra_entropy", value: 0 }, + { name: "Protocol_major_ver", value: 8 }, + { name: "Protocol_minor_ver", value: 0 }, + { name: "Min_utxo", value: 4310 }, + { name: "Min_pool_cost", value: 170000000 }, + { name: "Price_mem", value: 0.0577 }, + { name: "Price_step", value: 0.0000721 }, + { name: "Max_tx_ex_mem", value: 14000000 }, + { name: "Max_tx_ex_steps", value: 10000000000 }, + { name: "Max_block_ex_mem", value: 62000000 }, + { name: "Max_block_ex_steps", value: 20000000000 }, + { name: "Max_val_size", value: 5000 }, + { name: "Collateral_percent", value: 150 }, + { name: "Max_collateral_inputs", value: 3 }, + { name: "Coins_per_utxo_size", value: 4310 }, + { name: "Coins_per_utxo_word", value: 4310 }, +]; + +export const ByronPptParams = [ + { name: "Script_version", value: "0 " }, + { name: "Slot_duration", value: "20000 " }, + { name: "Max_block_size", value: "2000000 " }, + { name: "Max_header_size", value: "2000000 " }, + { name: "Max_tx_size", value: "4096 " }, + { name: "Max_proposal_size", value: "700 " }, + { name: "Mpc_thd", value: "20000000000000 " }, + { name: "Heavy_del_thd", value: "300000000000 " }, + { name: "Update_vote_thd", value: "1000000000000 " }, + { name: "Update_proposal_thd", value: "100000000000000 " }, + { name: "Update_implicit", value: "10000 " }, + { + name: "Soft_fork_rule", + value: "(900000000000000, 600000000000000, 50000000000000)", + }, + { name: "Summand", value: "155381 " }, + { name: "Multiplier", value: "44 " }, + { name: "Unlock_stake_epoch", value: "18446744073709551615" }, +]; + +export function decimalToFraction(decimal: number): [number, number] { + let numerator = decimal; + let denominator = 1; + let prevNumerator = 0; + let prevDenominator = 1; + + while (Math.abs(numerator - prevNumerator) > 6) { + prevNumerator = numerator; + prevDenominator = denominator; + numerator = Math.floor(numerator); + denominator = 1 / (decimal - numerator); + } + + return [prevNumerator, prevDenominator]; +} From 1482c8309a4844cc3abc2f9bd075e2e3bd7a3145 Mon Sep 17 00:00:00 2001 From: sara Date: Thu, 18 Apr 2024 17:47:32 -0300 Subject: [PATCH 13/16] refactor: front end components --- napi-pallas/src/validations/babbage.rs | 12 +- napi-pallas/src/validations/shelley_ma.rs | 8 +- web/app/components.tsx | 486 ------------------ web/app/components/Button.tsx | 33 ++ web/app/components/DataSection.tsx | 54 ++ web/app/components/Input.tsx | 31 ++ web/app/components/RootSection.tsx | 56 ++ .../Configurations/Configurations.tsx | 60 +++ .../Validations/Configurations/Tabs.tsx | 167 ++++++ .../components/Validations/Information.tsx | 73 +++ web/app/components/constructors.tsx | 56 ++ web/app/components/index.tsx | 13 + web/app/interfaces.ts | 8 +- web/app/routes/address.tsx | 12 +- web/app/routes/block-wip.tsx | 12 +- web/app/routes/tx.tsx | 27 +- web/app/utils.ts | 30 +- 17 files changed, 610 insertions(+), 528 deletions(-) delete mode 100644 web/app/components.tsx create mode 100644 web/app/components/Button.tsx create mode 100644 web/app/components/DataSection.tsx create mode 100644 web/app/components/Input.tsx create mode 100644 web/app/components/RootSection.tsx create mode 100644 web/app/components/Validations/Configurations/Configurations.tsx create mode 100644 web/app/components/Validations/Configurations/Tabs.tsx create mode 100644 web/app/components/Validations/Information.tsx create mode 100644 web/app/components/constructors.tsx create mode 100644 web/app/components/index.tsx diff --git a/napi-pallas/src/validations/babbage.rs b/napi-pallas/src/validations/babbage.rs index 716fe86..e75ce8c 100644 --- a/napi-pallas/src/validations/babbage.rs +++ b/napi-pallas/src/validations/babbage.rs @@ -302,19 +302,19 @@ pub fn validate_babbage(mtx_b: &BabbageMintedTx, context: ValidationContext) -> desired_number_of_stake_pools: context.n_opt, pool_pledge_influence: RationalNumber { numerator: context.a0_numerator as u64, - denominator: context.a0_denominator as u64, // ? + denominator: context.a0_denominator as u64, }, expansion_rate: RationalNumber { numerator: context.rho_numerator as u64, - denominator: context.rho_denominator as u64, // ? + denominator: context.rho_denominator as u64, }, treasury_growth_rate: RationalNumber { numerator: context.tau_numerator as u64, - denominator: context.tau_denominator as u64, // ? + denominator: context.tau_denominator as u64, }, decentralization_constant: RationalNumber { numerator: context.decentralisation_param_numerator as u64, - denominator: context.decentralisation_param_denominator as u64, // ? + denominator: context.decentralisation_param_denominator as u64, }, extra_entropy: Nonce { variant: NonceVariant::NeutralNonce, @@ -333,11 +333,11 @@ pub fn validate_babbage(mtx_b: &BabbageMintedTx, context: ValidationContext) -> execution_costs: ExUnitPrices { mem_price: RationalNumber { numerator: context.price_mem_numerator as u64, - denominator: context.price_mem_denominator as u64, // ? + denominator: context.price_mem_denominator as u64, }, step_price: RationalNumber { numerator: context.price_step_numerator as u64, - denominator: context.price_step_denominator as u64, // ? + denominator: context.price_step_denominator as u64, }, }, max_tx_ex_units: ExUnits { diff --git a/napi-pallas/src/validations/shelley_ma.rs b/napi-pallas/src/validations/shelley_ma.rs index 64bf861..569e642 100644 --- a/napi-pallas/src/validations/shelley_ma.rs +++ b/napi-pallas/src/validations/shelley_ma.rs @@ -223,19 +223,19 @@ pub fn validate_shelley_ma( desired_number_of_stake_pools: context.n_opt, pool_pledge_influence: RationalNumber { numerator: context.a0_numerator as u64, - denominator: context.a0_denominator as u64, // ? + denominator: context.a0_denominator as u64, }, expansion_rate: RationalNumber { numerator: context.rho_numerator as u64, - denominator: context.rho_denominator as u64, // ? + denominator: context.rho_denominator as u64, }, treasury_growth_rate: RationalNumber { numerator: context.tau_numerator as u64, - denominator: context.tau_denominator as u64, // ? + denominator: context.tau_denominator as u64, }, decentralization_constant: RationalNumber { numerator: context.decentralisation_param_numerator as u64, - denominator: context.decentralisation_param_denominator as u64, // ? + denominator: context.decentralisation_param_denominator as u64, }, extra_entropy: Nonce { variant: NonceVariant::NeutralNonce, diff --git a/web/app/components.tsx b/web/app/components.tsx deleted file mode 100644 index bda7c9b..0000000 --- a/web/app/components.tsx +++ /dev/null @@ -1,486 +0,0 @@ -import { Attribute, type Section } from "napi-pallas"; -import { PropsWithChildren, useEffect, useState } from "react"; -import { - DataProps, - EraType, - Eras, - IContext, - IValidation, - NetworkType, - ProtocolType, - TabType, -} from "./interfaces"; -import { ByronPptParams } from "./utils"; - -export type TopicMeta = { - title: string; - description?: React.ReactElement; -}; - -function getTopicMeta( - key: string | undefined, - all: Record -): TopicMeta { - return ( - all[key!] || { - title: key, - } - ); -} - -export function PropBlock(props: { - data: Attribute; - topics: Record; -}) { - const topic = getTopicMeta(props.data.topic, props.topics); - - return ( -
- {topic.description} -
-
{topic.title}
- {props.data.value || "(empty)"} -
-
- ); -} - -export function HexBlock(props: { name: string; value: string }) { - return ( -
-
{props.name}
- {props.value} -
- ); -} - -export function Paragraph(props: PropsWithChildren) { - return

{props.children}

; -} - -export const P1 = Paragraph; - -export function RootSection(props: { - data: Section; - topics: Record; - validations: IValidation[]; - era: string; -}) { - const [open, setOpen] = useState(false); - const handleClick = () => setOpen(!open); - const topic = getTopicMeta(props.data.topic, props.topics); - - if (props.data.error) - return ( -
-

{topic.description}

- {props.data.error} -
- ); - - return ( -
-
- - {open && } -
-

{topic.title}

- {!!props.data.bytes && ( - - )} - {props.data.attributes?.map((c) => ( - - ))} - {props.data.children?.map((c) => ( - - ))} -
- ); -} - -export function DataSection(props: { - data: Section; - topics: Record; -}) { - const topic = getTopicMeta(props.data.topic, props.topics); - const [open, setOpen] = useState(true); - const handleClick = () => setOpen(!open); - - return ( -
- - {open && ( - <> - {topic.description} - {!!props.data.error && ( -
- {props.data.error} -
- )} - {props.data.attributes?.map((c) => ( - - ))} - {props.data.children?.map((c) => ( - - ))} - {!props.data.attributes?.length && !props.data.children?.length && ( - - )} - {!!props.data.bytes && ( - - )} - - )} -
- ); -} - -export function EmptyBlock() { - return ( -
- Empty -
- ); -} - -export function Button( - props: PropsWithChildren<{ type: "submit" | "button" }> -) { - return ( - - ); -} - -export function TextArea(props: { name: string; placeholder?: string }) { - return ( -