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