#!/usr/bin/env bash # propose-bank-send.sh — submit a bank.send proposal to a DAO's proposal-single module. # # The canonical first-proposal pattern: agent address proposes a treasury transfer, # the sub-DAO votes (1-of-1 auto-passes), VetoConfig timelock opens, vetoer can veto # during the window, anyone can execute after. # # Usage: # propose-bank-send.sh \ # --proposal-module juno1propmod... \ # --title "Pay vendor invoice 42" \ # --description "Quarterly retainer per agreement of 2026-05-01." \ # --recipient juno1vendor... \ # --amount 100000000 \ # ujuno # --denom ujuno \ # --key my-key \ # --keyring-dir /workspace/.my-keyring \ # [--rpc https://juno-rpc.publicnode.com:443] \ # [--chain-id juno-1] \ # [--dry-run] # # Amount is in micro-units (ujuno = 1e-6 JUNO). 1 JUNO = 1000000ujuno. # # This script only submits the propose tx. To vote / execute, see the runbook # in references/dao-dao.md §Member. set -euo pipefail PROP_MOD="" TITLE="" DESCRIPTION="" RECIPIENT="" AMOUNT="" DENOM="ujuno" KEY="" KEYRING_DIR="" KEYRING_BACKEND="test" RPC="https://juno-rpc.publicnode.com:443" CHAIN_ID="juno-1" DRY_RUN=0 usage() { sed -n '2,22p' "$0" | sed 's/^# \{0,1\}//' ; exit "${1:-0}" ; } while [ $# -gt 0 ]; do case "$1" in --proposal-module) PROP_MOD="$2"; shift 2 ;; --title) TITLE="$2"; shift 2 ;; --description) DESCRIPTION="$2"; shift 2 ;; --recipient) RECIPIENT="$2"; shift 2 ;; --amount) AMOUNT="$2"; shift 2 ;; --denom) DENOM="$2"; shift 2 ;; --key) KEY="$2"; shift 2 ;; --keyring-dir) KEYRING_DIR="$2"; shift 2 ;; --keyring-backend) KEYRING_BACKEND="$2"; shift 2 ;; --rpc) RPC="$2"; shift 2 ;; --chain-id) CHAIN_ID="$2"; shift 2 ;; --dry-run) DRY_RUN=1; shift ;; -h|--help) usage 0 ;; *) echo "unknown flag: $1" >&2; usage 1 ;; esac done for required in PROP_MOD TITLE DESCRIPTION RECIPIENT AMOUNT KEY KEYRING_DIR ; do if [ -z "${!required}" ]; then echo "missing required: --${required,,}" >&2 usage 1 fi done WORK=$(mktemp -d) trap 'rm -rf "$WORK"' EXIT PROPOSE_MSG=$(jq -n \ --arg title "$TITLE" \ --arg desc "$DESCRIPTION" \ --arg to "$RECIPIENT" \ --arg amt "$AMOUNT" \ --arg denom "$DENOM" \ '{ propose: { title: $title, description: $desc, msgs: [ { bank: { send: { to_address: $to, amount: [{ denom: $denom, amount: $amt }] } } } ] } }') echo "$PROPOSE_MSG" > "$WORK/propose.json" echo "==> propose msg:" jq . "$WORK/propose.json" if [ "$DRY_RUN" -eq 1 ]; then echo "==> --dry-run set; would broadcast against $PROP_MOD on $CHAIN_ID" exit 0 fi echo "==> broadcasting to $PROP_MOD on $CHAIN_ID" junod tx wasm execute "$PROP_MOD" "$(cat "$WORK/propose.json")" \ --from "$KEY" \ --keyring-backend "$KEYRING_BACKEND" \ --keyring-dir "$KEYRING_DIR" \ --chain-id "$CHAIN_ID" \ --node "$RPC" \ --gas auto --gas-adjustment 1.4 \ --gas-prices 0.075ujuno \ --yes \ -o json | tee "$WORK/broadcast.json" | jq '.txhash, .code, .raw_log' TXHASH=$(jq -r '.txhash' "$WORK/broadcast.json") echo echo "==> broadcast txhash: $TXHASH" echo " proposal_id will be in the wasm event attributes once included" echo " next steps:" echo " verify-tx.sh --txhash $TXHASH --rpc $RPC # gets proposal_id" echo " junod tx wasm execute $PROP_MOD '{\"vote\":{\"proposal_id\":,\"vote\":\"yes\"}}' ..." echo " # wait timelock window for vetoer" echo " junod tx wasm execute $PROP_MOD '{\"execute\":{\"proposal_id\":}}' ..."