diff --git a/scripts/metadata-create.sh b/scripts/metadata-create.sh index 2f55e39..67fe215 100755 --- a/scripts/metadata-create.sh +++ b/scripts/metadata-create.sh @@ -3,8 +3,8 @@ ################################################## # Default configuration values -METADATA_COMMON_URL="https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/schemas/common.jsonld" - +METADATA_169_COMMON_URL="https://raw.githubusercontent.com/Ryun1/CIPs/refs/heads/cip-governance-metadata-extension/cip-governance-metadata-extension/cip169.common.jsonld" +METADATA_108_COMMON_URL="https://raw.githubusercontent.com/Ryun1/CIPs/refs/heads/cip-governance-metadata-extension/CIP-0108/cip-0108.common.jsonld" ################################################## # Exit immediately if a command exits with a non-zero status, @@ -30,6 +30,11 @@ if ! command -v pandoc >/dev/null 2>&1; then exit 1 fi +# Check if cardano-cli is installed (needed for deposit querying) +if ! command -v cardano-cli >/dev/null 2>&1; then + echo -e "${YELLOW}Warning: cardano-cli is not installed. Deposit amount will need to be provided manually.${NC}" >&2 +fi + # Usage message usage() { local col=50 @@ -118,7 +123,7 @@ fi echo -e " " echo -e "${YELLOW}Creating a governance action metadata file from a markdown file${NC}" echo -e "${CYAN}This script assumes a basic structure for the markdown file, using H2 headers${NC}" -echo -e "${CYAN}This script uses Intersect's governance action schemas (extended CIP108)${NC}" +echo -e "${CYAN}This script uses CIP169 governance metadata extension with CIP-116 ProposalProcedure format${NC}" # Generate output filename: same directory and name as input, but with .jsonld extension input_dir=$(dirname "$input_file") @@ -165,6 +170,96 @@ get_section_last() { } +# Query governance action deposit from chain (required for CIP-116 ProposalProcedure format) +# Returns the deposit amount in lovelace, or "null" if query fails +query_governance_deposit() { + # Check if cardano-cli is available + if ! command -v cardano-cli >/dev/null 2>&1; then + echo -e "${YELLOW}Warning: cardano-cli not found. Cannot query deposit from chain.${NC}" >&2 + echo "null" + return 1 + fi + + # Check if node socket path is set + if [ -z "${CARDANO_NODE_SOCKET_PATH:-}" ]; then + echo -e "${YELLOW}Warning: CARDANO_NODE_SOCKET_PATH not set. Cannot query deposit from chain.${NC}" >&2 + echo "null" + return 1 + fi + + # Check if network id is set + if [ -z "${CARDANO_NODE_NETWORK_ID:-}" ]; then + echo -e "${YELLOW}Warning: CARDANO_NODE_NETWORK_ID not set. Cannot query deposit from chain.${NC}" >&2 + echo "null" + return 1 + fi + + # Determine network flag + local network_flag="" + if [ "$CARDANO_NODE_NETWORK_ID" = "764824073" ] || [ "$CARDANO_NODE_NETWORK_ID" = "mainnet" ]; then + network_flag="--mainnet" + else + network_flag="--testnet-magic $CARDANO_NODE_NETWORK_ID" + fi + + # Query deposit amount + local deposit + deposit=$(cardano-cli conway query gov-state $network_flag 2>/dev/null | jq -r '.currentPParams.govActionDeposit // empty' 2>/dev/null) + + if [ -z "$deposit" ] || [ "$deposit" = "null" ] || [ "$deposit" = "" ]; then + echo -e "${YELLOW}Warning: Could not query deposit from chain.${NC}" >&2 + echo "null" + return 1 + fi + + echo "$deposit" + return 0 +} + +query_governance_state_prev_actions() { + # Check if cardano-cli is available + if ! command -v cardano-cli >/dev/null 2>&1; then + echo -e "${YELLOW}Warning: cardano-cli not found. Cannot query deposit from chain.${NC}" >&2 + echo "null" + return 1 + fi + + # Check if node socket path is set + if [ -z "${CARDANO_NODE_SOCKET_PATH:-}" ]; then + echo -e "${YELLOW}Warning: CARDANO_NODE_SOCKET_PATH not set. Cannot query deposit from chain.${NC}" >&2 + echo "null" + return 1 + fi + + # Check if network id is set + if [ -z "${CARDANO_NODE_NETWORK_ID:-}" ]; then + echo -e "${YELLOW}Warning: CARDANO_NODE_NETWORK_ID not set. Cannot query deposit from chain.${NC}" >&2 + echo "null" + return 1 + fi + + # Determine network flag + local network_flag="" + if [ "$CARDANO_NODE_NETWORK_ID" = "764824073" ] || [ "$CARDANO_NODE_NETWORK_ID" = "mainnet" ]; then + network_flag="--mainnet" + else + network_flag="--testnet-magic $CARDANO_NODE_NETWORK_ID" + fi + + # Query previous governance state + local gov_state + + gov_state=$(cardano-cli conway query gov-state | jq -r '.nextRatifyState.nextEnactState.prevGovActionIds') + + if [ -z "$gov_state" ] || [ "$gov_state" = "null" ] || [ "$gov_state" = "" ]; then + echo -e "${YELLOW}Warning: Could not query governance state from chain.${NC}" >&2 + echo "null" + return 1 + fi + + echo "$gov_state" + return 0 +} # Extract references from References section extract_references() { awk ' @@ -213,25 +308,56 @@ extract_references() { ' "$TEMP_MD" } -# Generate onChain property for info governance action +# Generate onChain property for info governance action (CIP-116 ProposalProcedure format) generate_info_onchain() { + local deposit_amount + deposit_amount=$(query_governance_deposit) + + # If deposit query failed, use null (JSON null, not string) + local deposit_json + if [ "$deposit_amount" = "null" ] || [ -z "$deposit_amount" ]; then + deposit_json="null" + else + deposit_json="$deposit_amount" + fi + cat <&2 +echo -e "${CYAN}Downloading CIP-108 context from $METADATA_108_COMMON_URL...${NC}" +TEMP_CIP108=$(mktemp /tmp/metadata_create_cip108.XXXXXX) +if ! curl -sSfL "$METADATA_108_COMMON_URL" -o "$TEMP_CIP108"; then + echo -e "${RED}Error: Failed to download context from $METADATA_108_COMMON_URL${NC}" >&2 + rm -f "$TEMP_CIP108" exit 1 fi +echo -e "${CYAN}Downloading CIP-169 context from $METADATA_169_COMMON_URL...${NC}" +TEMP_CIP169=$(mktemp /tmp/metadata_create_cip169.XXXXXX) +if ! curl -sSfL "$METADATA_169_COMMON_URL" -o "$TEMP_CIP169"; then + echo -e "${RED}Error: Failed to download context from $METADATA_169_COMMON_URL${NC}" >&2 + rm -f "$TEMP_CIP108" "$TEMP_CIP169" + exit 1 +fi + +echo -e "${CYAN}Merging CIP-108 and CIP-169 contexts...${NC}" +# Merge contexts: use CIP-108 as base and add/update with contents from CIP-169 +# jq -s '.[0] * .[1]' "$TEMP_CIP108" "$TEMP_CIP169" > "$TEMP_CONTEXT" + +# Build gov_action context based on governance action type +if [ "$governance_action_type" = "info" ]; then + GOV_ACTION_CONTEXT='{ + "@id": "CIP116:GovAction", + "@context": { + "tag": "CIP116:info_action" + } + }' +else + GOV_ACTION_CONTEXT='{ + "@id": "CIP116:GovAction" + }' +fi + +jq -s --argjson gov_action_ctx "$GOV_ACTION_CONTEXT" '{ + "@context": { + CIP100: .[0]["@context"].CIP100, + CIP108: .[0]["@context"].CIP108, + CIP116: .[1]["@context"].CIP116, + CIP169: .[1]["@context"].CIP169, + hashAlgorithm: .[0]["@context"].hashAlgorithm, + body: { + "@id": .[0]["@context"].body["@id"], + "@context": (.[0]["@context"].body["@context"] * { + onChain: { + "@id": "CIP169:onChain", + "@context": { + deposit: { + "@id": "CIP116:deposit", + "@type": "CIP116:UInt64" + }, + reward_account: { + "@id": "CIP116:reward_account", + "@type": "CIP116:RewardAddress" + }, + gov_action: $gov_action_ctx + } + } + }) + }, + authors: .[0]["@context"].authors + } +}' "$TEMP_CIP108" "$TEMP_CIP169" > "$TEMP_CONTEXT" + +rm -f "$TEMP_CIP108" "$TEMP_CIP169" + +# Build the metadata JSON-LD with CIP-116 ProposalProcedure format onChain property jq --argjson context "$(cat "$TEMP_CONTEXT")" \ --argjson title "$TITLE" \ --argjson abstract "$ABSTRACT" \ diff --git a/scripts/metadata-validate.sh b/scripts/metadata-validate.sh index 8ebaf41..77b2519 100755 --- a/scripts/metadata-validate.sh +++ b/scripts/metadata-validate.sh @@ -13,6 +13,7 @@ NC='\033[0m' UNDERLINE='\033[4m' BOLD='\033[1m' GRAY='\033[0;90m' +WHITE='\033[1;37m' ################################################## # Default schema URLs @@ -20,16 +21,20 @@ CIP_100_SCHEMA="https://raw.githubusercontent.com/cardano-foundation/CIPs/refs/h CIP_108_SCHEMA="https://raw.githubusercontent.com/cardano-foundation/CIPs/refs/heads/master/CIP-0108/cip-0108.common.schema.json" CIP_119_SCHEMA="https://raw.githubusercontent.com/cardano-foundation/CIPs/refs/heads/master/CIP-0119/cip-0119.common.schema.json" CIP_136_SCHEMA="https://raw.githubusercontent.com/cardano-foundation/CIPs/refs/heads/master/CIP-0136/cip-136.common.schema.json" +CIP_169_SCHEMA="https://raw.githubusercontent.com/elenabardho/CIPs/refs/heads/cip-governance-metadata-extension-schema/cip-governance-metadata-extension/cip-0169.common.schema.json" INTERSECT_TREASURY_SCHEMA="https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/schemas/treasury-withdrawals/common.schema.json" INTERSECT_INFO_SCHEMA="https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/schemas/info/common.schema.json" INTERSECT_PPU_SCHEMA="https://raw.githubusercontent.com/IntersectMBO/governance-actions/refs/heads/main/schemas/parameter-changes/common.schema.json" # Default schema values +# CIP-169 is the default as it extends CIP-100 with on-chain effects verification +# When CIP-169 is used, CIP-116 is automatically included for reference resolution DEFAULT_USE_CIP_100="false" DEFAULT_USE_CIP_108="false" DEFAULT_USE_CIP_119="false" DEFAULT_USE_CIP_136="false" -DEFAULT_USE_INTERSECT="true" +DEFAULT_USE_CIP_169="false" +DEFAULT_USE_INTERSECT="false" ################################################## # Check if cardano-signer is installed @@ -77,7 +82,8 @@ usage() { printf " ${GREEN}%-*s${NC}${GRAY}%s${NC}\n" $((col-8)) "[--cip108]" "- Compare against CIP-108 Governance actions schema (default: $DEFAULT_USE_CIP_108)" printf " ${GREEN}%-*s${NC}${GRAY}%s${NC}\n" $((col-8)) "[--cip119]" "- Compare against CIP-119 DRep schema (default: $DEFAULT_USE_CIP_119)" printf " ${GREEN}%-*s${NC}${GRAY}%s${NC}\n" $((col-8)) "[--cip136]" "- Compare against CIP-136 CC vote schema (default: $DEFAULT_USE_CIP_136)" - printf " ${GREEN}%-*s${NC}${GRAY}%s${NC}\n" $((col-8)) "[--no-intersect-schema]" "- Don't compare against Intersect governance action schemas (default: $DEFAULT_USE_INTERSECT)" + printf " ${GREEN}%-*s${NC}${GRAY}%s${NC}\n" $((col-8)) "[--cip169]" "- Compare against CIP-169 Governance metadata schema (default: $DEFAULT_USE_CIP_169, includes CIP-116)" + printf " ${GREEN}%-*s${NC}${GRAY}%s${NC}\n" $((col-8)) "[--intersect-schema]" "- Compare against Intersect governance action schemas (default: $DEFAULT_USE_INTERSECT)" printf " ${GREEN}%-*s${NC}${GRAY}%s${NC}\n" $((col-8)) "[--schema URL]" "- Compare against schema at URL" printf " ${GREEN}%-*s${NC}${GRAY}%s${NC}\n" $((col-8)) "[--dict FILE]" "- Use custom aspell dictionary file (optional)" printf " ${GREEN}%-*s${GRAY}%s${NC}\n" $((col-8)) "-h, --help" "- Show this help message and exit" @@ -90,6 +96,7 @@ use_cip_108="$DEFAULT_USE_CIP_108" use_cip_100="$DEFAULT_USE_CIP_100" use_cip_119="$DEFAULT_USE_CIP_119" use_cip_136="$DEFAULT_USE_CIP_136" +use_cip_169="$DEFAULT_USE_CIP_169" use_intersect_schema="$DEFAULT_USE_INTERSECT" user_schema_url="" user_schema="false" @@ -114,8 +121,12 @@ while [[ $# -gt 0 ]]; do use_cip_136="true" shift ;; - --no-intersect-schema) - use_intersect_schema="false" + --cip169) + use_cip_169="true" + shift + ;; + --intersect-schema) + use_intersect_schema="true" shift ;; --schema) @@ -254,6 +265,12 @@ if [ "$use_cip_136" = "true" ]; then curl -sSfSL "$CIP_136_SCHEMA" -o "$TEMP_CIP_136_SCHEMA" fi +if [ "$use_cip_169" = "true" ]; then + echo -e "${WHITE}Downloading CIP-169 Governance Metadata Extension schema...${NC}" + TEMP_CIP_169_SCHEMA="$TMP_SCHEMAS_DIR/cip-169-schema.json" + curl -sSfSL "$CIP_169_SCHEMA" -o "$TEMP_CIP_169_SCHEMA" +fi + # Determine which Intersect schema to use based on governanceActionType property if [ "$use_intersect_schema" = "true" ]; then governance_action_type=$(jq -r '.body.onChain.governanceActionType' "$JSON_FILE") @@ -286,11 +303,12 @@ fi # Validate the JSON file against the schemas schemas=("$TMP_SCHEMAS_DIR"/*-schema.json) VALIDATION_FAILED=0 + for schema in "${schemas[@]}"; do echo -e " " echo -e "${CYAN}Validating against schema: ${YELLOW}$schema${NC}" if [ -f "$schema" ]; then - ajv validate -s "$schema" -d "$JSON_FILE" --all-errors --strict=true + ajv validate -s "$schema" -d "$JSON_FILE" --all-errors --strict=false if [ $? -ne 0 ]; then VALIDATION_FAILED=1 fi