diff --git a/scripts/action-create-info.sh b/scripts/action-create-info.sh index f4e99f0..07b4808 100755 --- a/scripts/action-create-info.sh +++ b/scripts/action-create-info.sh @@ -129,7 +129,7 @@ echo -e "${CYAN}Doing some basic validation and checks on metadata${NC}" check_field() { local field_name="$1" local field_value="$2" - + if [ -z "$field_value" ] || [ "$field_value" = "null" ]; then echo -e "${RED}Error: Required field '$field_name' not found in metadata${NC}" >&2 exit 1 @@ -140,22 +140,25 @@ check_field() { title=$(jq -r '.body.title' "$input_file") check_field "title" "$title" -ga_type=$(jq -r '.body.onChain.governanceActionType' "$input_file") -check_field "governanceActionType" "$ga_type" +ga_type=$(jq -r '.body.onChain.gov_action.tag' "$input_file") +check_field "tag" "$ga_type" + +deposit_return=$(jq -r '.body.onChain.reward_account' "$input_file") +check_field "reward_account" "$deposit_return" -deposit_return=$(jq -r '.body.onChain.depositReturnAddress' "$input_file") -check_field "depositReturnAddress" "$deposit_return" +deposit=$(jq -r '.body.onChain.deposit' "$input_file") +check_field "deposit" "$deposit" authors=$(jq -r '.authors' "$input_file") check_field "authors" "$authors" witness=$(jq -r '.authors[0].witness' "$input_file") check_field "witness" "$witness" -if [ "$ga_type" = "info" ]; then - echo "Metadata has correct governanceActionType" +if [ "$ga_type" = "info_action" ]; then + echo "Metadata has correct governance action tag" else - echo "Metadata does not have the correct governanceActionType" - echo "Expected: info found: $ga_type" + echo "Metadata does not have the correct governance action tag" + echo "Expected: info_action found: $ga_type" exit 1 fi @@ -222,7 +225,7 @@ is_stake_address_script() { is_stake_address_registered(){ local address="$1" - stake_address_deposit=$(cardano-cli conway query stake-address-info --address "$address" | jq -r '.[0].delegationDeposit') + stake_address_deposit=$(cardano-cli conway query stake-address-info --address "$address" | jq -r '.[0].stakeRegistrationDeposit') if [ "$stake_address_deposit" != "null" ]; then return 0 else diff --git a/scripts/action-create-tw.sh b/scripts/action-create-tw.sh index d28156e..c47b4e9 100755 --- a/scripts/action-create-tw.sh +++ b/scripts/action-create-tw.sh @@ -163,28 +163,34 @@ check_field() { title=$(jq -r '.body.title' "$input_file") check_field "title" "$title" -ga_type=$(jq -r '.body.onChain.governanceActionType' "$input_file") -check_field "governanceActionType" "$ga_type" +ga_type=$(jq -r '.body.onChain.gov_action.tag' "$input_file") +check_field "tag" "$ga_type" -deposit_return=$(jq -r '.body.onChain.depositReturnAddress' "$input_file") -check_field "depositReturnAddress" "$deposit_return" +deposit_return=$(jq -r '.body.onChain.reward_account' "$input_file") +check_field "reward_account" "$deposit_return" + +deposit_amount=$(jq -r '.body.onChain.deposit' "$input_file") +check_field "deposit" "$deposit_amount" + +withdrawal_list=$(jq -r '.body.onChain.gov_action.rewards' "$input_file") +check_field "rewards" "$withdrawal_list" # todo: support multiple withdrawals -withdrawal_address=$(jq -r '.body.onChain.withdrawals[0].withdrawalAddress' "$input_file") -check_field "withdrawalAddress" "$withdrawal_address" -withdrawal_amount=$(jq -r '.body.onChain.withdrawals[0].withdrawalAmount' "$input_file") -check_field "withdrawalAmount" "$withdrawal_amount" +withdrawal_address=$(jq -r '.body.onChain.gov_action.rewards[0].key' "$input_file") +check_field "key" "$withdrawal_address" +withdrawal_amount=$(jq -r '.body.onChain.gov_action.rewards[0].value' "$input_file") +check_field "value" "$withdrawal_amount" authors=$(jq -r '.authors' "$input_file") check_field "authors" "$authors" witness=$(jq -r '.authors[0].witness' "$input_file") check_field "witness" "$witness" -if [ "$ga_type" = "treasuryWithdrawals" ]; then +if [ "$ga_type" = "treasury_withdrawals_action" ]; then echo "Metadata has correct governanceActionType" else echo "Metadata does not have the correct governanceActionType" - echo "Expected: treasuryWithdrawals found: $ga_type" + echo "Expected: treasury_withdrawals_action found: $ga_type" exit 1 fi @@ -292,7 +298,7 @@ fi is_stake_address_registered(){ local address="$1" - stake_address_deposit=$(cardano-cli conway query stake-address-info --address "$address" | jq -r '.[0].delegationDeposit') + stake_address_deposit=$(cardano-cli conway query stake-address-info --address "$address" | jq -r '.[0].stakeRegistrationDeposit') if [ "$stake_address_deposit" != "null" ]; then return 0 else diff --git a/scripts/metadata-create.sh b/scripts/metadata-create.sh index 2f55e39..50098bb 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" + } + }' +elif [ "$governance_action_type" = "treasury" ]; then + echo "hello" + GOV_ACTION_CONTEXT='{ + "@id": "CIP116:GovAction", + "@context": { + "tag": "CIP116:treasury_withdrawals_action", + "rewards": { + "@id": "CIP116:rewards", + "@container": "@set" + }, + "key": { + "@id": "CIP116:rewardAddress", + "@type": "CIP116:RewardAddress" + }, + "value": { + "@id": "CIP116:amount", + "@type": "CIP116:UInt64" + } + } + }' +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..52b7ea9 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") @@ -285,12 +302,19 @@ fi # Validate the JSON file against the schemas schemas=("$TMP_SCHEMAS_DIR"/*-schema.json) + +if [ -z "$(ls -A $TMP_SCHEMAS_DIR)" ]; then + echo -e "${RED}Error: No schemas were downloaded.${NC}" + exit 1 +fi + 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