diff --git a/docs/2025-budget-withdrawals.md b/docs/2025-budget-withdrawals.md index e90a5bd..76627ff 100644 --- a/docs/2025-budget-withdrawals.md +++ b/docs/2025-budget-withdrawals.md @@ -24,8 +24,10 @@ source ./scripts/.env Set some useful variables ```shell -export DEPOSIT_RETURN_ADDR="" -export WITHDRAWAL_ADDR="" +export DEPOSIT_RETURN_ADDR="stake1uyvjdz9rxsfsmv44rtk75k2rqyqskrga96dgdfrqjvjjpwsefcjnp" +export WITHDRAWAL_ADDR="stake17xzc8pt7fgf0lc0x7eq6z7z6puhsxmzktna7dluahrj6g6ghh5qjr" + +export a="../governance-actions/mainnet/2025-07-13-budget-2025" ``` Make sure that `CARDANO_NODE_NETWORK_ID` and `CARDANO_NODE_SOCKET_PATH` are set. @@ -75,7 +77,7 @@ We will pass `--no-author` as we know there is no author witness yet. We will pass `--no-ipfs` as we know we didn't put it on ipfs yet. ```shell -./scripts/budget-metadata-validate.sh ./my-metadata-directory --no-author --no-ipfs --deposit-return-addr $DEPOSIT_RETURN_ADDR --withdrawal-addr $WITHDRAWAL_ADDR +./scripts/budget-metadata-validate.sh $a/EC --no-author --no-ipfs --deposit-return-addr $DEPOSIT_RETURN_ADDR --withdrawal-addr $WITHDRAWAL_ADDR ``` ### 6. Sign with author's key diff --git a/scripts/action-create-tw.sh b/scripts/action-create-tw.sh index e1aa737..09f7d76 100755 --- a/scripts/action-create-tw.sh +++ b/scripts/action-create-tw.sh @@ -3,7 +3,7 @@ ################################################## # Default configuration values -WITHDRAW_TO_SCRIPT="false" +WITHDRAW_TO_SCRIPT="true" ################################################## @@ -36,9 +36,9 @@ fi # Usage message usage() { - echo "Usage: $0 [--withdraw-to-script] [--deposit-return-addr ] [--withdrawal-addr ]" + echo "Usage: $0 [--withdraw-to-script] [--deposit-return-addr ] [--withdrawal-addr ]" echo "Options:" - echo " Path to the JSON-LD metadata file or directory containing metadata files" + echo " Path to the JSON-LD metadata file" echo " --withdraw-to-script Check that the withdrawal address is a script-based address, exit otherwise" echo " --deposit-return-addr Check that metadata deposit return address matches provided one (Bech32)" echo " --withdrawal-addr Check that metadata withdrawal address matches provided one (Bech32)" @@ -302,7 +302,7 @@ fi is_stake_address_delegated_to_abstain_or_null() { local address="$1" - vote_delegation=$(cardano-cli conway query stake-address-info --$protocol_magic --address "$address" | jq -r '.[0].voteDelegation') + vote_delegation=$(cardano-cli conway query stake-address-info --address "$address" | jq -r '.[0].voteDelegation') if [ "$vote_delegation" = "alwaysAbstain" ] || [ "$vote_delegation" = "null" ] ; then return 0 else diff --git a/scripts/author-create.sh b/scripts/author-create.sh index 8b334b6..79be66f 100755 --- a/scripts/author-create.sh +++ b/scripts/author-create.sh @@ -162,15 +162,19 @@ sign_file() { # Use cardano-signer to sign author metadata if [ -d "$input_path" ]; then - # If input is a directory: sign all .jsonld files + # If input is a directory: sign all .jsonld files (including subdirectories) echo -e " " echo -e "${CYAN}Processing directory: ${YELLOW}$input_path${NC}" - shopt -s nullglob - jsonld_files=("$input_path"/*.jsonld) + # Get all .jsonld files in the directory and subdirectories + jsonld_files=() + while IFS= read -r -d '' file; do + jsonld_files+=("$file") + done < <(find "$input_path" -type f -name "*.jsonld" -print0) + # check if any .jsonld files were found if [ ${#jsonld_files[@]} -eq 0 ]; then - echo -e "${RED}Error: No .jsonld files found in directory '$input_path'.${NC}" >&2 + echo -e "${RED}Error: No .jsonld files found in directory (including subdirectories): ${YELLOW}$input_path${NC}" >&2 exit 1 fi diff --git a/scripts/author-validate.sh b/scripts/author-validate.sh index 3ba6122..1d3bd6c 100755 --- a/scripts/author-validate.sh +++ b/scripts/author-validate.sh @@ -48,9 +48,19 @@ echo -e " " # https://github.com/gitmachtl/cardano-signer?tab=readme-ov-file#verify-governance-metadata-and-the-authors-signatures verify_author_witness() { local file="$1" - cardano-signer verify --cip100 \ + local output + output=$(cardano-signer verify --cip100 \ --data-file "$file" \ - --json-extended | jq '{workMode, result, errorMsg, authors, canonizedHash, fileHash}' + --json-extended | jq '{workMode, result, errorMsg, authors, canonizedHash, fileHash}') + + echo "$output" + + local result + result=$(echo "$output" | jq -r '.result') + if [ "$result" != "true" ]; then + echo -e "${RED}Error: Verification failed with result: ${YELLOW}$result${NC}" >&2 + exit 1 + fi } # Give the user a warning if the author isn't Intersect diff --git a/scripts/budget-action-create.sh b/scripts/budget-action-create.sh new file mode 100755 index 0000000..9cb3bb5 --- /dev/null +++ b/scripts/budget-action-create.sh @@ -0,0 +1,186 @@ +#!/bin/bash + +################################################## + +# some options maybe + +################################################## + +# Exit immediately if a command exits with a non-zero status, +# treat unset variables as an error, and fail if any command in a pipeline fails +set -euo pipefail + +# Colors +#BLACK='\033[0;30m' +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[0;33m' +BLUE='\033[0;34m' +CYAN='\033[0;36m' +BRIGHTWHITE='\033[0;37;1m' +NC='\033[0m' + +# Check if cardano-cli is installed +if ! command -v cardano-cli >/dev/null 2>&1; then + echo "Error: cardano-cli is not installed or not in your PATH." >&2 + exit 1 +fi + +# Check if ipfs cli is installed +if ! command -v ipfs >/dev/null 2>&1; then + echo "Error: ipfs cli is not installed or not in your PATH." >&2 + exit 1 +fi + +# Usage message +usage() { + echo "Usage: $0 --deposit-return-addr --withdrawal-addr [--no-ipfs-pin]" + echo "Create treasury withdrawal governance actions from a directory of JSONLD metadata files and host the metadata on ipfs." + echo "Options:" + echo " Path to directory containing .jsonld files" + echo " --deposit-return-addr Check that metadata deposit return address matches provided one (Bech32) [REQUIRED]" + echo " --withdrawal-addr Check that metadata withdrawal address matches provided one (Bech32) [REQUIRED]" + echo " --no-ipfs-pin Skip IPFS pinning step" + echo " -h, --help Show this help message and exit" + exit 1 +} + +# Initialize variables with defaults +input_path="" +deposit_return_address_input="" +withdrawal_address_input="" +skip_ipfs_pin="false" + +# Parse command line arguments +while [[ $# -gt 0 ]]; do + case $1 in + --deposit-return-addr) + if [ -n "${2:-}" ]; then + deposit_return_address_input="$2" + shift 2 + else + echo -e "${RED}Error: --deposit-return-addr requires a value${NC}" >&2 + usage + fi + ;; + --withdrawal-addr) + if [ -n "${2:-}" ]; then + withdrawal_address_input="$2" + shift 2 + else + echo -e "${RED}Error: --withdrawal-addr requires a value${NC}" >&2 + usage + fi + ;; + --no-ipfs-pin) + skip_ipfs_pin="true" + shift + ;; + -h|--help) + usage + ;; + *) + if [ -z "$input_path" ]; then + input_path="$1" + fi + shift + ;; + esac +done + +# If no input path provided, show usage +if [ -z "$input_path" ]; then + echo -e "${RED}Error: No directory specified${NC}" >&2 + usage +fi + +# Check if required parameters are provided +if [ -z "$deposit_return_address_input" ]; then + echo -e "${RED}Error: --deposit-return-addr is required${NC}" >&2 + usage +fi + +if [ -z "$withdrawal_address_input" ]; then + echo -e "${RED}Error: --withdrawal-addr is required${NC}" >&2 + usage +fi + +# Check if input is a directory +if [ ! -d "$input_path" ]; then + echo -e "${RED}Error: Input is not a valid directory: ${YELLOW}$input_path${NC}" >&2 + exit 1 +fi + +echo -e " " +echo -e "${YELLOW}Budget Action Creation Service${NC}" +echo -e "${CYAN}This script processes JSONLD files to create treasury withdrawal governance actions${NC}" +echo -e "${CYAN}It will host files on IPFS and create governance actions for each file${NC}" + +# Get all .jsonld files in the directory and subdirectories +jsonld_files=() +while IFS= read -r -d '' file; do + jsonld_files+=("$file") +done < <(find "$input_path" -type f -name "*.jsonld" -print0) + +# Check if any .jsonld files were found +if [ ${#jsonld_files[@]} -eq 0 ]; then + echo -e " " + echo -e "${RED}Error: No .jsonld files found in directory (including subdirectories): ${YELLOW}$input_path${NC}" >&2 + exit 1 +fi + +echo -e " " +echo -e "${CYAN}Found ${YELLOW}${#jsonld_files[@]}${NC}${CYAN} .jsonld files to process${NC}" + +for file in "${jsonld_files[@]}"; do + # Ask user if they want to continue with the next file + # Skip for the first file + if [ "$file" != "${jsonld_files[0]}" ]; then + echo -e " " + echo -e "${CYAN}The next file is: ${YELLOW}$file${NC}" + read -p "Do you want to continue with the next file? (y/n): " choice + case "$choice" in + y|Y ) echo -e "${GREEN}Continuing with the next file...${NC}";; + n|N ) echo -e "${YELLOW}Exiting...${NC}"; exit 0;; + * ) echo -e "${RED}Invalid choice, exiting...${NC}"; exit 1;; + esac + fi + + if [ -f "$file" ]; then + echo -e " " + echo -e "${CYAN}Processing file: ${YELLOW}$file${NC}" + echo -e "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + + if [ "$skip_ipfs_pin" = "false" ]; then + echo -e " " + echo -e "${CYAN}Hosting file on IPFS using ./ipfs-pin.sh${NC}" + ./scripts/ipfs-pin.sh "$file" + echo -e "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + else + echo -e " " + echo -e "${YELLOW}Skipping IPFS pinning step${NC}" + echo -e "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + fi + + echo -e " " + echo -e "${CYAN}Creating treasury governance action using ./action-create-tw.sh${NC}" + + ./scripts/action-create-tw.sh --deposit-return-addr "$deposit_return_address_input" \ + --withdrawal-addr "$withdrawal_address_input" \ + "$file" + + echo -e "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + echo -e " " + echo -e "${GREEN}Successfully processed: ${YELLOW}$file${NC}" + echo -e "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + + else + echo -e " " + echo -e "${RED}Error: file is not a valid file: ${YELLOW}$file${NC}" >&2 + exit 1 + fi +done + +echo -e " " +echo -e "${GREEN}All files processed successfully!${NC}" +echo -e "${CYAN}Treasury withdrawal governance actions have been created for all JSONLD files${NC}" diff --git a/scripts/budget-metadata-validate.sh b/scripts/budget-metadata-validate.sh index d9f3692..05b5df6 100755 --- a/scripts/budget-metadata-validate.sh +++ b/scripts/budget-metadata-validate.sh @@ -172,6 +172,10 @@ if [ -d "$input_path" ]; then check_field "title" "$title" abstract=$(jq -r '.body.abstract' "$file") check_field "abstract" "$abstract" + motivation=$(jq -r '.body.motivation' "$file") + check_field "motivation" "$motivation" + rationale=$(jq -r '.body.rationale' "$file") + check_field "rationale" "$rationale" references=$(jq -r '.body.references' "$file") check_field "references" "$references" ga_type=$(jq -r '.body.onChain.governanceActionType' "$file") @@ -201,8 +205,15 @@ if [ -d "$input_path" ]; then echo "Title does not contain the term 'ada'" fi + if [[ "$abstract" == *".mark"* ]] || [[ "$motivation" == *".mark"* ]] || [[ "$rationale" == *".mark"* ]]; then + echo -e "${RED}Error: The term '.mark' is not allowed in the title or abstract!" >&2 + exit 1 + else + echo "no Marks !!!" + fi + # ensure that title is less than 81 characters - if [ ${#title} -gt 81 ]; then + if [ ${#title} -gt 80 ]; then echo -e "${RED}Error: Title is too long, must be less than 80 characters" >&2 exit 1 else diff --git a/scripts/cardano-aspell-dict.txt b/scripts/cardano-aspell-dict.txt index b140ba9..1612fcf 100644 --- a/scripts/cardano-aspell-dict.txt +++ b/scripts/cardano-aspell-dict.txt @@ -142,12 +142,117 @@ Assurer modularity blogpost CDH +Pallas +BitcoinOS +Partnerchain +Fluidtokens +Tokeo +CBOR +FTE +cryptographic +zkFold +Blockfrost's +webhook +IOG's +integrations CSV +acffc +ae +ghh +dbb +qjr Dquadrant Blockfrost uptime +TVL incentivized +SDK +xzc +RPC +reusability +SDKs +AdaLite +UI +DEX +Trezor +Vacuumlabs +WingRiders +Yoroi +cli +fintech +lang +Nixpkgs +reproducibly +composability +provers +zkBridge +Eryx +FFTs +Lambdaworks +Nethermind +Noir +PhDs +Plonky +ENCOINS +CircleSTARKS +zkRollup +Cexplorer +io +BAU +UX +Adapools +Cexplorer +CIPs +frontend +Scalus +organisations +dev +optimisations +specialised +CDN +FTs +CAPEX +Centralised +IPFS +middleware +NFTCDN +BloxBean +CCL +Yaci +JVM +Satya +DevKit +TWEAG's +Peras +benchmarking +verifiability +Tweag +transformative +DevKit +Arweave +Oleksandr +Nemish +DSL +DevOps +verifiers +relayer +bugfixing +OSC +OSO +hardforks +eDSL +Plutonomicon +GovTool +Github +Gerolamo +Eternl +Dolos +NFT +TestNet +ZKP Ekklesia +TPS +hw EOY knowledgebase MLabs diff --git a/scripts/cip-108-create-human-readable.sh b/scripts/cip-108-create-human-readable.sh index 67dc834..0a62200 100755 --- a/scripts/cip-108-create-human-readable.sh +++ b/scripts/cip-108-create-human-readable.sh @@ -53,9 +53,24 @@ if [ $# -eq 0 ]; then exit 1 fi -# If the argument is a directory, process each JSON-LD file +# If the argument is a directory, process each JSON-LD file (including subdirectories) if [ -d "$1" ]; then - for jsonld_file in "$1"/*.jsonld; do + # Get all .jsonld files in the directory and subdirectories + jsonld_files=() + while IFS= read -r -d '' file; do + jsonld_files+=("$file") + done < <(find "$1" -type f -name "*.jsonld" -print0) + + # Check if any .jsonld files were found + if [ ${#jsonld_files[@]} -eq 0 ]; then + echo "Error: No .jsonld files found in directory (including subdirectories): $1" + exit 1 + fi + + echo "Found ${#jsonld_files[@]} .jsonld files to process" + + # Process each .jsonld file + for jsonld_file in "${jsonld_files[@]}"; do extract_jsonld_data "$jsonld_file" done elif [ -f "$1" ]; then diff --git a/scripts/ipfs-pin.sh b/scripts/ipfs-pin.sh index cff52f0..48b9c12 100755 --- a/scripts/ipfs-pin.sh +++ b/scripts/ipfs-pin.sh @@ -265,15 +265,19 @@ EOF # Main processing logic if [ -d "$input_path" ]; then - # If input is a directory: pin all .jsonld files + # If input is a directory: pin all .jsonld files (including subdirectories) echo -e " " echo -e "${CYAN}Processing directory: ${YELLOW}$input_path${NC}" - shopt -s nullglob - jsonld_files=("$input_path"/*.jsonld) + # Get all .jsonld files in the directory and subdirectories + jsonld_files=() + while IFS= read -r -d '' file; do + jsonld_files+=("$file") + done < <(find "$input_path" -type f -name "*.jsonld" -print0) + # check if any .jsonld files were found if [ ${#jsonld_files[@]} -eq 0 ]; then - echo -e "${RED}Error: No .jsonld files found in directory: ${YELLOW}$input_path${NC}" >&2 + echo -e "${RED}Error: No .jsonld files found in directory (including subdirectories): ${YELLOW}$input_path${NC}" >&2 exit 1 fi diff --git a/scripts/metadata-create.sh b/scripts/metadata-create.sh index 2aa4a3f..9600e88 100755 --- a/scripts/metadata-create.sh +++ b/scripts/metadata-create.sh @@ -153,36 +153,66 @@ extract_references() { awk ' BEGIN { in_refs = 0 - label = "" + current_label = "" ref_count = 0 } /^References$/ { in_refs = 1; next } - /^Authors$/ { in_refs = 0 } + /^Authors$/ { in_refs = 0; next } in_refs { + # Skip empty lines if ($0 ~ /^\s*$/) next - if ($0 ~ /^- \[/ || $0 ~ /^- ipfs:\/\//) { + # Check for reference lines (markdown links or direct URLs) + if ($0 ~ /^- \[.*\]\(.*\)/ || $0 ~ /^- ipfs:\/\// || $0 ~ /^- https?:\/\//) { uri = "" - - if (index($0, "(") > 0 && index($0, ")") > 0) { + label = current_label + + if ($0 ~ /^- \[.*\]\(.*\)/) { + # Extract label from markdown link [label](url) + link_label = $0 + sub(/^- \[/, "", link_label) + sub(/\]\(.*\).*$/, "", link_label) + # Extract URL from markdown link uri = $0 sub(/^.*\(/, "", uri) sub(/\).*$/, "", uri) - } else if ($0 ~ /- ipfs:\/\//) { - split($0, parts, "- ") - uri = parts[2] + + # Use the link label if we don t have a preceding label + if (current_label == "") { + label = link_label + } + } else if ($0 ~ /^- ipfs:\/\// || $0 ~ /^- https?:\/\//) { + # Direct URL reference + uri = $0 + sub(/^- /, "", uri) + + # If no preceding label, use the URI as label + if (current_label == "") { + label = uri + } } + # Clean up quotes in label and URI gsub(/"/, "\\\"", label) gsub(/"/, "\\\"", uri) - refs[ref_count++] = " {\"@type\": \"Other\", \"label\": \"" label "\", \"uri\": \"" uri "\"}" - label = "" + # Only add if we have a URI + if (uri != "") { + refs[ref_count++] = " {\"@type\": \"Other\", \"label\": \"" label "\", \"uri\": \"" uri "\"}" + } + + # Reset current label after processing a reference + current_label = "" } else { - label = $0 + # This line is part of a label - accumulate it + if (current_label == "") { + current_label = $0 + } else { + current_label = current_label " " $0 + } } } @@ -201,7 +231,7 @@ extract_references() { # this search term can be changed to match the expected pattern extract_withdrawal_address() { local rationale_text="$1" - echo "$rationale_text" | jq -r . | grep -oE "With the confirmed withdrawal address being:[[:space:]]*(stake_test1[a-zA-Z0-9]{53}|stake1[a-zA-Z0-9]{53})" | sed -E 's/.*being:[[:space:]]*//' + echo "$rationale_text" | jq -r . | grep -oE "With the confirmed treasury reserve contract address being:[[:space:]]*(stake_test1[a-zA-Z0-9]{53}|stake1[a-zA-Z0-9]{53})" | sed -E 's/.*being:[[:space:]]*//' } # use helper functions to extract sections @@ -254,21 +284,17 @@ cat < "$TEMP_OUTPUT_JSON" "abstract": "CIP108:abstract", "motivation": "CIP108:motivation", "rationale": "CIP108:rationale", - "@context": { - "onChain": { - "@id": "intersectSpec:onChain", - "@context": { - "governanceActionType": "intersectSpec:governanceActionType", - "depositReturnAddress": "intersectSpec:depositReturnAddress", + "onChain": { + "@id": "intersectSpec:onChain", + "@context": { + "governanceActionType": "intersectSpec:governanceActionType", + "depositReturnAddress": "intersectSpec:depositReturnAddress", + "withdrawals": { + "@id": "intersectSpec:withdrawals", + "@container": "@set", "@context": { - "withdrawals": { - "@id": "intersectSpec:withdrawals", - "@container": "@set", - "@context": { - "withdrawalAddress": "intersectSpec:withdrawalAddress", - "withdrawalAmount": "intersectSpec:withdrawalAmount" - } - } + "withdrawalAddress": "intersectSpec:withdrawalAddress", + "withdrawalAmount": "intersectSpec:withdrawalAmount" } } } @@ -316,6 +342,12 @@ EOF echo -e " " echo -e "${CYAN}Cleaning up the formatting on the JSON output...${NC}" +# for debug +# echo "$(cat $TEMP_OUTPUT_JSON)" + +# Use jq to format the JSON output +jq . "$TEMP_OUTPUT_JSON" > "$FINAL_OUTPUT_JSON" + # Clean up for markdown formatting already present within the .docx file # replace \\*\\* with ** (remove escaped asterisks) perl -i -pe 's/\\\\\*\\\\\*/\*\*/g' "$FINAL_OUTPUT_JSON" @@ -332,11 +364,13 @@ perl -i -pe 's/\\\\\x27/\x27/g' "$FINAL_OUTPUT_JSON" # replace \' with ' # give up on this one for now -# for debug -# echo "$(cat $TEMP_OUTPUT_JSON)" +# remove any instances of \n\nReferences +perl -i -pe 's/\\n\\nReferences//g' "$FINAL_OUTPUT_JSON" -# Use jq to format the JSON output -jq . "$TEMP_OUTPUT_JSON" > "$FINAL_OUTPUT_JSON" +# replace **[Smart Contract Guide**](https://docs.intersectmbo.org/cardano-facilitation-services/cardano-budget/intersect-administration-services/smart-contracts-as-part-of-our-administration) +# with **[Smart Contract Guide](https://docs.intersectmbo.org/cardano-facilitation-services/cardano-budget/intersect-administration-services/smart-contracts-as-part-of-our-administration)** +# i know, i know, this is a bit of a hack, but it works +perl -i -pe 's/\*\*\[Smart Contract Guide\*\*\]\(https:\/\/docs\.intersectmbo\.org\/cardano-facilitation-services\/cardano-budget\/intersect-administration-services\/smart-contracts-as-part-of-our-administration\)/\*\*\[Smart Contract Guide\]\(https:\/\/docs\.intersectmbo\.org\/cardano-facilitation-services\/cardano-budget\/intersect-administration-services\/smart-contracts-as-part-of-our-administration\)\*\*/g' "$FINAL_OUTPUT_JSON" # Clean up trailing \n\n from JSON string fields echo -e "${CYAN}Removing trailing newlines from JSON fields...${NC}" diff --git a/scripts/metadata-validate.sh b/scripts/metadata-validate.sh index 9e1aeaa..be41d34 100755 --- a/scripts/metadata-validate.sh +++ b/scripts/metadata-validate.sh @@ -26,6 +26,8 @@ if ! command -v ajv >/dev/null 2>&1; then exit 1 fi +set -euo pipefail + # Usage message usage() { echo "Usage: $0 [--cip108] [--cip100] [--cip136] [--intersect-treasury] [--schema URL] [--dict FILE]" @@ -220,4 +222,4 @@ echo " " echo "Validation complete." echo " " -exit 0 \ No newline at end of file +# exit $AJV_EXIT_CODE \ No newline at end of file