diff --git a/HACKING.md b/HACKING.md
index 60bbef84f2..08fee5e621 100644
--- a/HACKING.md
+++ b/HACKING.md
@@ -93,8 +93,10 @@ order to avoid conflicts. Here is an overview of the ports used:
| ----- | --------------------- | ------------------------------------------------------------------------------------- |
| 1317 | wasmd LCD API | @cosmjs/launchpad and @cosmjs/cosmwasm tests |
| 1318 | simapp API | Manual Stargate debugging |
+| 1319 | wasmd LCD API | Manual Stargate debugging |
| 4444 | socketserver | @cosmjs/sockets tests |
| 4445 | socketserver slow | @cosmjs/sockets tests |
| 11133 | Tendermint 0.33 RPC | @cosmjs/tendermint-rpc tests |
| 11134 | Tendermint 0.34 RPC | @cosmjs/tendermint-rpc tests ([soon™](https://github.com/CosmWasm/cosmjs/issues/344)) |
| 26658 | simapp Tendermint RPC | Stargate client tests |
+| 26659 | wasmd Tendermint RPC | @cosmjs/cosmwasm tests |
diff --git a/packages/faucet/package.json b/packages/faucet/package.json
index bd6b088c28..71def4f607 100644
--- a/packages/faucet/package.json
+++ b/packages/faucet/package.json
@@ -36,7 +36,7 @@
"test-node": "node jasmine-testrunner.js",
"test": "yarn build-or-skip && yarn test-node",
"coverage": "nyc --reporter=text --reporter=lcov yarn test --quiet",
- "start-dev": "FAUCET_CREDIT_AMOUNT_UCOSM=10000000 FAUCET_CREDIT_AMOUNT_USTAKE=100000 FAUCET_CONCURRENCY=3 FAUCET_MNEMONIC=\"economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone\" ./bin/cosmos-faucet start \"http://localhost:26658\"",
+ "start-dev": "FAUCET_ADDRESS_PREFIX=wasm FAUCET_CREDIT_AMOUNT_UCOSM=10000000 FAUCET_CREDIT_AMOUNT_USTAKE=100000 FAUCET_CONCURRENCY=3 FAUCET_MNEMONIC=\"economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone\" ./bin/cosmos-faucet start \"http://localhost:26659\"",
"start-coralnet": "FAUCET_ADDRESS_PREFIX=coral FAUCET_TOKENS=\"ushell,ureef\" FAUCET_CREDIT_AMOUNT_USHELL=10000000 FAUCET_CREDIT_AMOUNT_UREEF=2000000 FAUCET_CONCURRENCY=3 FAUCET_MNEMONIC=\"economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone\" ./bin/cosmos-faucet start \"https://lcd.coralnet.cosmwasm.com\""
},
"dependencies": {
diff --git a/scripts/wasmd/README.md b/scripts/wasmd/README.md
new file mode 100644
index 0000000000..b63249ba74
--- /dev/null
+++ b/scripts/wasmd/README.md
@@ -0,0 +1,152 @@
+# Local Stargate development network with CosmWasm support
+
+## Starting the blockchain
+
+Run the following:
+
+```
+cd scripts/wasmd
+./start.sh && ./init.sh
+```
+
+## CLI
+
+Docker-friendly access to `wasmd` is provided. Just use the `./cli.sh` script.
+For example:
+
+```
+./cli.sh status
+```
+
+This should give you output similar to the following if your blockchain is
+running:
+
+```json
+{
+ "node_info": {
+ "protocol_version": { "p2p": "7", "block": "10", "app": "0" },
+ "id": "223aedddd9442bcf16641858ca85837f27997d0d",
+ "listen_addr": "tcp://0.0.0.0:26656",
+ "network": "testing",
+ "version": "0.32.2",
+ "channels": "4020212223303800",
+ "moniker": "testing",
+ "other": { "tx_index": "on", "rpc_address": "tcp://127.0.0.1:26657" }
+ },
+ "sync_info": {
+ "latest_block_hash": "3E3BEBCFA4E47BC67C7DE44DD4E83D8D42235DE75DA942A6BECD1F0F5A6246E4",
+ "latest_app_hash": "73A3641BDEFBB728B1B48FB87B510F3E76E3B4519BC4954C6E1060738FCE8B14",
+ "latest_block_height": "1217",
+ "latest_block_time": "2019-09-26T15:44:13.0111312Z",
+ "catching_up": false
+ },
+ "validator_info": {
+ "address": "3A7EBE1A9E333146AE5D9FCB765B88BDD4D2859A",
+ "pub_key": {
+ "type": "tendermint/PubKeyEd25519",
+ "value": "3ZYx1HKwT/llXzYC2yVeWEiWHd6uBQ7Bi7jiDFczx28="
+ },
+ "voting_power": "100"
+ }
+}
+```
+
+## Adding the validator key to your keybase
+
+The Cosmos test network is initialised with a validator (see
+`.gaiad/config/genesis.json`). This validator has the following mnemonic:
+
+```
+economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone
+```
+
+To add the validator key to your local keybase run the following, choose an
+encryption passphrase (e.g. `testing123`) and enter the above mnemonic when
+prompted:
+
+```
+./cli.sh keys add validator --recover
+```
+
+You should get output matching the following:
+
+```
+- name: validator
+ type: local
+ address: cosmos1pkptre7fdkl6gfrzlesjjvhxhlc3r4gmmk8rs6
+ pubkey: cosmospub1addwnpepqd8sgxq7aw348ydctp3n5ajufgxp395hksxjzc6565yfp56scupfqhlgyg5
+ mnemonic: ""
+ threshold: 0
+ pubkeys: []
+```
+
+## Preset accounts
+
+1. **Faucet**
+ economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone
+ Address 0: wasm1pkptre7fdkl6gfrzlesjjvhxhlc3r4gm32kke3
+ Address 1: wasm10dyr9899g6t0pelew4nvf4j5c3jcgv0r5d3a5l
+ Address 2: wasm1xy4yqngt0nlkdcenxymg8tenrghmek4n3u2lwa
+ Address 3: wasm142u9fgcjdlycfcez3lw8x6x5h7rfjlnfaallkd
+ Address 4: wasm1hsm76p4ahyhl5yh3ve9ur49r5kemhp2r93f89d
+ Pubkey 0: A08EGB7ro1ORuFhjOnZcSgwYlpe0DSFjVNUIkNNQxwKQ
+ Pubkey 1: AiDosfIbBi54XJ1QjCeApumcy/FjdtF+YhywPf3DKTx7
+ Pubkey 2: AzQg33JZqH7vSsm09esZY5bZvmzYwE/SY78cA0iLxpD7
+ Pubkey 3: A3gOAlB6aiRTCPvWMQg2+ZbGYNsLd8qlvV28m8p2UhY2
+ Pubkey 4: Aum2063ub/ErUnIUB36sK55LktGUStgcbSiaAnL1wadu
+2. **Alice**: Test account for the cosmwasm package that can run in parallel with faucet without sequence conflicts
+ enlist hip relief stomach skate base shallow young switch frequent cry park
+ Address 0: wasm14qemq0vw6y3gc3u3e0aty2e764u4gs5lndxgyk
+ Address 1: wasm1hhg2rlu9jscacku2wwckws7932qqqu8xm5ca8y
+ Address 2: wasm1xv9tklw7d82sezh9haa573wufgy59vmwnxhnsl
+ Address 3: wasm17yg9mssjenmc3jkqth6ulcwj9cxujrxxg9nmzk
+ Address 4: wasm1f7j7ryulwjfe9ljplvhtcaxa6wqgula3nh873j
+ Pubkey 0: A9cXhWb8ZpqCzkA8dQCPV29KdeRLV3rUYxrkHudLbQtS
+ Pubkey 1: A4XluzvcUx0ViLF0DjYW5/noArGwpltDstoUUZo+g1b0
+ Pubkey 2: A5TKr1NKc/MKRJ7+EHDD9PlzmGaPD/di/6hzZyBwxoy5
+ Pubkey 3: A/HSABDUqMB2qDy+PA7fiuuuA+hfrco2VwwiThMiTzUx
+ Pubkey 4: A7usTiqgqfxL/WKhoephDUSCHBQlLagtwI/qTmEteTRM
+3. **Bob**: Test account (unused for now)
+ remain fragile remove stamp quiz bus country dress critic mammal office need
+ Address 0: wasm1lvrwcvrqlc5ktzp2c4t22xgkx29q3y83426at5
+ Address 1: wasm1vkv9sfwaak76weyamqx0flmng2vuquxqjq3flu
+ Address 2: wasm106jwym4s9aujcmes26myzzwqsccw09sd3nap5h
+ Address 3: wasm1c7wpeen2uv8thayf7g8q2rgpm29clj0dzlu7t9
+ Address 4: wasm1mjxpv9ft30wer7ma7kwfxhm42l379xuttrjcl3
+ Pubkey 0: A0d/GxY+UALE+miWJP0qyq4/EayG1G6tsg24v+cbD6By
+ Pubkey 1: Agqd6njsVEQD1CR+F2aqEb8hil5NXZ06mjKgetaNC12t
+ Pubkey 2: A6e9ElvKaM0DKWh1bIdK3bgB14dyEDgIXYMA0Lbs1GoQ
+ Pubkey 3: AkAK5PQaucieWMb0+tTRY01feYI+upRnoNK556eD0Ibb
+ Pubkey 4: A5HMVEAJsupdQWItbZv5Z1xZifDixQi6tjU/hJpZY1bF
+4. **Unused**: for testing account state; this account never changes balances or sequences
+ oyster design unusual machine spread century engine gravity focus cave carry slot
+ ArkCaFUJ/IH+vKBmNRCdUVl3mCAhbopk9jjW4Ko4OfRQ
+ wasm1cjsxept9rkggzxztslae9ndgpdyt240842kpxh
+5. **Guest**: account for manual testing
+ degree tackle suggest window test behind mesh extra cover prepare oak script
+ Am/+YV0LaeqQPu7BDJuDHV7J8y68ptkGs10YS+9s71Nq
+ wasm17d0jcz59jf68g52vq38tuuncmwwjk42us8fnse
+6. **Ledger**: accounts for Ledger based demos and tests
+ example indicate trick cereal hub fix civil host kiss version bird dash
+ Address 0: wasm1p6xs63q4g7np99ttv5nd3yzkt8n4qxa45jkgsk
+ Address 1: wasm1meeu3jl268txxytwmmrsljk8rawh6n2mhwp76p
+ Address 2: wasm1cak6lnpfxs035xd88sq8e4zujsm8g2g953hfan
+ Address 3: wasm1x3x8kyypx8z6q7fx3gw65x29mhl5gg8qtf4xkg
+ Address 4: wasm18c27m2rj4lg74md03ujralvt562c097nd7scqw
+ Address 5: wasm1q2y53e6x7s5mlddtd2qkcjr3nwr4dszvs4js2q
+ Address 6: wasm1paa2gstlk7c98n27dw2g6tp6fyqvf32m3x04t6
+ Address 7: wasm1rvxjd8k6xvssz2eerfzemvat35pttfgrsz43tx
+ Address 8: wasm12zejt8d9xl70jd2333p4p265m2nr9h8g6pgmly
+ Address 9: wasm1exctm2036jtwyc9v3ftqfzmgnv9tdhj2sskt4u
+ Address 10: wasm1f3pws3ztnp3s4nn5zxqdrl9vlqv5avkq3rjfe7
+ Pubkey 0: A66JoCNaNSXDsyj4qW7JgqXPTz5rOnfE6EKEArf4jJEK
+ Pubkey 1: AtvmGuZvEN3NwL05BQdxl3XygUf+Vl/930fhFMt1HTyU
+ Pubkey 2: A58dfmfVoKoTCteEzTHBC0OLJIBgzejGDVVEb8YW9vtJ
+ Pubkey 3: A1wA01EixwcWJkdhI69ckGuQDX0NimhLCYdrQCegkOJF
+ Pubkey 4: A9juq+VbP26qtVh71ANlwwJQ+ABTWIyHEKYrVwjmbYE6
+ Pubkey 5: Ar4VUqiRYl75+TF3AExX8at3deeLj2O9mNMtBq2aVpym
+ Pubkey 6: Ak/JoSXzu6+Rp2W0wT6CqfZfzlDOwebl7xVF/zmKX99Y
+ Pubkey 7: AtmLZZGHeCiNuroPAzBK2NKeXKT68SwioLj4I8Oj35Mn
+ Pubkey 8: AuaUr9GEMUBKeZrJD/dv9QL/zJmMxX7OA/sjRrvBFXS2
+ Pubkey 9: AiV5uMzvzoD7hlF+GhYuRCnf8tP+0AlPMbtfVoYv3InI
+ Pubkey 10: A2ZnLEcbpyjS30H5UF1vezq29aBcT9oo5EARATIW9Cpj
diff --git a/scripts/wasmd/cli.sh b/scripts/wasmd/cli.sh
new file mode 100755
index 0000000000..ed3a19f6f7
--- /dev/null
+++ b/scripts/wasmd/cli.sh
@@ -0,0 +1,21 @@
+#!/bin/bash
+set -o errexit -o nounset -o pipefail
+command -v shellcheck > /dev/null && shellcheck "$0"
+
+SCRIPT_DIR="$(realpath "$(dirname "$0")")"
+# shellcheck source=./env
+# shellcheck disable=SC1091
+source "$SCRIPT_DIR"/env
+
+# TODO: make this run as UID? Does this matter?
+HOME_DIR="/root"
+
+docker run \
+ --rm \
+ -it \
+ --mount type=volume,source=wasmd_data,target=/root/.wasmd \
+ -w "$HOME_DIR" \
+ --env "HOME=$HOME_DIR" \
+ --net "container:$CONTAINER_NAME" \
+ "$REPOSITORY:$VERSION" \
+ wasmd "$@"
diff --git a/scripts/wasmd/env b/scripts/wasmd/env
new file mode 100644
index 0000000000..cfb4b02980
--- /dev/null
+++ b/scripts/wasmd/env
@@ -0,0 +1,5 @@
+# Choose from https://hub.docker.com/r/cosmwasm/wasmd/tags
+REPOSITORY="cosmwasm/wasmd"
+VERSION="v0.12.0"
+
+CONTAINER_NAME="wasmd"
diff --git a/scripts/wasmd/generate_addresses.js b/scripts/wasmd/generate_addresses.js
new file mode 100755
index 0000000000..3ed7814567
--- /dev/null
+++ b/scripts/wasmd/generate_addresses.js
@@ -0,0 +1,63 @@
+#!/usr/bin/env node
+
+/* eslint-disable @typescript-eslint/naming-convention */
+const { encodeSecp256k1Pubkey, makeCosmoshubPath, Secp256k1HdWallet } = require("@cosmjs/launchpad");
+
+const prefix = "wasm";
+const accountsToCreate = [
+ {
+ mnemonic:
+ "economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone",
+ accountNumbers: [0, 1, 2, 3, 4],
+ },
+ {
+ mnemonic: "enlist hip relief stomach skate base shallow young switch frequent cry park",
+ accountNumbers: [0, 1, 2, 3, 4],
+ },
+ {
+ mnemonic: "remain fragile remove stamp quiz bus country dress critic mammal office need",
+ accountNumbers: [0, 1, 2, 3, 4],
+ },
+ {
+ mnemonic: "oyster design unusual machine spread century engine gravity focus cave carry slot",
+ accountNumbers: [0],
+ },
+ {
+ mnemonic: "degree tackle suggest window test behind mesh extra cover prepare oak script",
+ accountNumbers: [0],
+ },
+
+ {
+ mnemonic: "example indicate trick cereal hub fix civil host kiss version bird dash",
+ accountNumbers: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
+ },
+];
+
+async function main() {
+ for (const { mnemonic, accountNumbers } of accountsToCreate) {
+ const wallets = await Promise.all(
+ accountNumbers.map((accountNumber) =>
+ Secp256k1HdWallet.fromMnemonic(mnemonic, makeCosmoshubPath(accountNumber), prefix),
+ ),
+ );
+ const accounts = (await Promise.all(wallets.map((wallet) => wallet.getAccounts()))).map(
+ (accountsForWallet) => accountsForWallet[0],
+ );
+
+ console.info("=".repeat(process.stdout.columns));
+ console.info("mnemonic:", mnemonic);
+ for (const { address, pubkey } of accounts) {
+ console.info("-".repeat(process.stdout.columns));
+ console.info("pubkey:", encodeSecp256k1Pubkey(pubkey).value);
+ console.info("address:", address);
+ }
+ }
+}
+
+main().then(
+ () => process.exit(0),
+ (error) => {
+ console.error(error);
+ process.exit(1);
+ },
+);
diff --git a/scripts/wasmd/generate_template.sh b/scripts/wasmd/generate_template.sh
new file mode 100755
index 0000000000..762abe2dbb
--- /dev/null
+++ b/scripts/wasmd/generate_template.sh
@@ -0,0 +1,66 @@
+#!/bin/bash
+set -o errexit -o nounset -o pipefail
+command -v shellcheck > /dev/null && shellcheck "$0"
+
+SCRIPT_DIR="$(realpath "$(dirname "$0")")"
+# shellcheck source=./env
+# shellcheck disable=SC1091
+source "$SCRIPT_DIR"/env
+
+rm -rf "$SCRIPT_DIR/template"
+mkdir "$SCRIPT_DIR/template"
+
+# The usage of the accounts below is documented in README.md of this directory
+docker run --rm \
+ -e PASSWORD=my-secret-password \
+ --mount type=bind,source="$SCRIPT_DIR/template",target=/root \
+ "$REPOSITORY:$VERSION" \
+ ./setup_wasmd.sh \
+wasm1pkptre7fdkl6gfrzlesjjvhxhlc3r4gm32kke3 wasm10dyr9899g6t0pelew4nvf4j5c3jcgv0r5d3a5l wasm1xy4yqngt0nlkdcenxymg8tenrghmek4n3u2lwa wasm142u9fgcjdlycfcez3lw8x6x5h7rfjlnfaallkd wasm1hsm76p4ahyhl5yh3ve9ur49r5kemhp2r93f89d \
+wasm14qemq0vw6y3gc3u3e0aty2e764u4gs5lndxgyk wasm1hhg2rlu9jscacku2wwckws7932qqqu8xm5ca8y wasm1xv9tklw7d82sezh9haa573wufgy59vmwnxhnsl wasm17yg9mssjenmc3jkqth6ulcwj9cxujrxxg9nmzk wasm1f7j7ryulwjfe9ljplvhtcaxa6wqgula3nh873j \
+wasm1lvrwcvrqlc5ktzp2c4t22xgkx29q3y83426at5 wasm1vkv9sfwaak76weyamqx0flmng2vuquxqjq3flu wasm106jwym4s9aujcmes26myzzwqsccw09sd3nap5h wasm1c7wpeen2uv8thayf7g8q2rgpm29clj0dzlu7t9 wasm1mjxpv9ft30wer7ma7kwfxhm42l379xuttrjcl3 \
+wasm1cjsxept9rkggzxztslae9ndgpdyt240842kpxh \
+wasm17d0jcz59jf68g52vq38tuuncmwwjk42us8fnse \
+wasm1p6xs63q4g7np99ttv5nd3yzkt8n4qxa45jkgsk wasm1meeu3jl268txxytwmmrsljk8rawh6n2mhwp76p wasm1cak6lnpfxs035xd88sq8e4zujsm8g2g953hfan wasm1x3x8kyypx8z6q7fx3gw65x29mhl5gg8qtf4xkg wasm18c27m2rj4lg74md03ujralvt562c097nd7scqw wasm1q2y53e6x7s5mlddtd2qkcjr3nwr4dszvs4js2q wasm1paa2gstlk7c98n27dw2g6tp6fyqvf32m3x04t6 wasm1rvxjd8k6xvssz2eerfzemvat35pttfgrsz43tx wasm12zejt8d9xl70jd2333p4p265m2nr9h8g6pgmly wasm1exctm2036jtwyc9v3ftqfzmgnv9tdhj2sskt4u wasm1f3pws3ztnp3s4nn5zxqdrl9vlqv5avkq3rjfe7
+
+# # The ./template folder is created by the docker daemon's user (root on Linux, current user
+# # when using Docker Desktop on macOS), let's make it ours if needed
+# if [ ! -x "$SCRIPT_DIR/template/.wasmd/config/gentx" ]; then
+# sudo chown -R "$(id -u):$(id -g)" "$SCRIPT_DIR/template"
+# fi
+
+# function inline_jq() {
+# IN_OUT_PATH="$1"
+# shift
+# TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/inline_jq.XXXXXXXXX")
+# TMP_FILE="$TMP_DIR/$(basename "$IN_OUT_PATH")"
+# jq "$@" < "$IN_OUT_PATH" > "$TMP_FILE"
+# if ! mv "$TMP_FILE" "$IN_OUT_PATH" ; then
+# >&2 echo "Temp file '$TMP_FILE' could not be deleted. If it contains sensitive data, you might want to delete it manually."
+# exit 3
+# fi
+# }
+
+# (
+# cd "$SCRIPT_DIR"
+# # Sort genesis
+# inline_jq "template/.wasmd/config/genesis.json" -S
+
+# # Custom settings in config.toml
+# sed -i "" \
+# -e 's/^cors_allowed_origins =.*$/cors_allowed_origins = ["*"]/' \
+# -e 's/^timeout_propose =.*$/timeout_propose = "300ms"/' \
+# -e 's/^timeout_propose_delta =.*$/timeout_propose_delta = "100ms"/' \
+# -e 's/^timeout_prevote =.*$/timeout_prevote = "300ms"/' \
+# -e 's/^timeout_prevote_delta =.*$/timeout_prevote_delta = "100ms"/' \
+# -e 's/^timeout_precommit =.*$/timeout_precommit = "300ms"/' \
+# -e 's/^timeout_precommit_delta =.*$/timeout_precommit_delta = "100ms"/' \
+# -e 's/^timeout_commit =.*$/timeout_commit = "1s"/' \
+# "template/.wasmd/config/config.toml"
+
+# # Custom settings app.toml
+# sed -i "" \
+# -e 's/^enable =.*$/enable = true/' \
+# -e 's/^enabled-unsafe-cors =.*$/enabled-unsafe-cors = true/' \
+# "template/.wasmd/config/app.toml"
+# )
diff --git a/scripts/wasmd/init.sh b/scripts/wasmd/init.sh
new file mode 100755
index 0000000000..cf511eaee0
--- /dev/null
+++ b/scripts/wasmd/init.sh
@@ -0,0 +1,34 @@
+#!/bin/bash
+set -o errexit -o nounset -o pipefail
+command -v shellcheck > /dev/null && shellcheck "$0"
+
+echo "Waiting for blockchain and REST server to be available ..."
+timeout 60 bash -c "until curl -s http://localhost:1319/node_info > /dev/null; do sleep 0.5; done"
+# The chain is unreliable in the first second of its existence (https://gist.github.com/webmaster128/8175692d4af5e6c572fddda7a9ef437c)
+sleep 1
+echo "Waiting for height to be > 1 ..."
+# sleep 10
+timeout 20 bash -c "until [ $(curl -s localhost:1319/blocks/latest | jq -r '.block.header.height // 0') -gt 1 ]; do sleep 0.5; done"
+echo "Okay, thank you for your patience."
+
+
+SCRIPT_DIR="$(realpath "$(dirname "$0")")"
+
+
+#
+# Cosmos SDK init
+#
+"$SCRIPT_DIR/send_first.js"
+
+# #
+# # CosmWasm init
+# #
+# (
+# echo "Ensuring contracts' checksums are correct ..."
+# cd "$SCRIPT_DIR/contracts"
+# sha256sum --check checksums.sha256
+# )
+# "$SCRIPT_DIR/deploy_hackatom.js"
+# "$SCRIPT_DIR/deploy_erc20.js"
+# "$SCRIPT_DIR/deploy_cw3.js"
+# # "$SCRIPT_DIR/deploy_nameservice.js"
diff --git a/scripts/wasmd/priv_validator_state.template.json b/scripts/wasmd/priv_validator_state.template.json
new file mode 100644
index 0000000000..0967ef424b
--- /dev/null
+++ b/scripts/wasmd/priv_validator_state.template.json
@@ -0,0 +1 @@
+{}
diff --git a/scripts/wasmd/send_first.js b/scripts/wasmd/send_first.js
new file mode 100755
index 0000000000..a390491f8f
--- /dev/null
+++ b/scripts/wasmd/send_first.js
@@ -0,0 +1,34 @@
+#!/usr/bin/env node
+
+/* eslint-disable @typescript-eslint/naming-convention */
+const { Random } = require("@cosmjs/crypto");
+const { Bech32 } = require("@cosmjs/encoding");
+const { coins } = require("@cosmjs/launchpad");
+const { DirectSecp256k1HdWallet } = require("@cosmjs/proto-signing");
+const { assertIsBroadcastTxSuccess, SigningStargateClient } = require("@cosmjs/stargate");
+
+const rpcUrl = "http://localhost:26659";
+const prefix = "wasm";
+const faucet = {
+ mnemonic:
+ "economy stock theory fatal elder harbor betray wasp final emotion task crumble siren bottom lizard educate guess current outdoor pair theory focus wife stone",
+ address0: "wasm1pkptre7fdkl6gfrzlesjjvhxhlc3r4gm32kke3",
+};
+
+async function main() {
+ const wallet = await DirectSecp256k1HdWallet.fromMnemonic(faucet.mnemonic, undefined, prefix);
+ const client = await SigningStargateClient.connectWithWallet(rpcUrl, wallet);
+ const recipient = Bech32.encode(prefix, Random.getBytes(20));
+ const amount = coins(226644, "ucosm");
+ const memo = "Ensure chain has my pubkey";
+ const sendResult = await client.sendTokens(faucet.address0, recipient, amount, memo);
+ assertIsBroadcastTxSuccess(sendResult);
+}
+
+main().then(
+ () => process.exit(0),
+ (error) => {
+ console.error(error);
+ process.exit(1);
+ },
+);
diff --git a/scripts/wasmd/start.sh b/scripts/wasmd/start.sh
new file mode 100755
index 0000000000..225c13a746
--- /dev/null
+++ b/scripts/wasmd/start.sh
@@ -0,0 +1,48 @@
+#!/bin/bash
+set -o errexit -o nounset -o pipefail
+command -v shellcheck > /dev/null && shellcheck "$0"
+
+# Please keep this in sync with the Ports overview in HACKING.md
+TENDERMINT_PORT_GUEST="26657"
+TENDERMINT_PORT_HOST="26659"
+LCD_API_PORT_GUEST="1317"
+LCD_API_PORT_HOST="1319"
+
+SCRIPT_DIR="$(realpath "$(dirname "$0")")"
+# shellcheck source=./env
+# shellcheck disable=SC1091
+source "$SCRIPT_DIR"/env
+
+TMP_DIR=$(mktemp -d "${TMPDIR:-/tmp}/wasmd.XXXXXXXXX")
+chmod 777 "$TMP_DIR"
+echo "Using temporary dir $TMP_DIR"
+WASMD_LOGFILE="$TMP_DIR/wasmd.log"
+
+# Use a fresh volume for every start
+docker volume rm -f wasmd_data
+
+echo "TEMPLATE: $SCRIPT_DIR/template"
+# This starts up wasmd
+docker run --rm \
+ --name "$CONTAINER_NAME" \
+ -p "$TENDERMINT_PORT_HOST":"$TENDERMINT_PORT_GUEST" \
+ -p "$LCD_API_PORT_HOST":"$LCD_API_PORT_GUEST" \
+ --mount type=bind,source="$SCRIPT_DIR/template",target=/template \
+ --mount type=volume,source=wasmd_data,target=/root \
+ "$REPOSITORY:$VERSION" \
+ ./run_wasmd.sh /template \
+ > "$WASMD_LOGFILE" &
+
+echo "wasmd running and logging into $WASMD_LOGFILE"
+
+# Debug chain start
+# sleep 3 && cat "$WASMD_LOGFILE"
+
+# # Use a large timeout because of potentially long image download in `docker run`
+# if ! timeout 180 bash -c "until [ \"\$( docker container inspect -f '{{.State.Status}}' \"$CONTAINER_NAME\" 2> /dev/null )\" = \"running\" ]; do sleep 0.5; done"; then
+# echo "Container named '$CONTAINER_NAME' not running. We cannot continue." \
+# "This can happen when 'docker run' needs too long to download and start." \
+# "It might be worth retrying this step once the image is in the local docker cache."
+# docker kill "$CONTAINER_NAME"
+# exit 1
+# fi
diff --git a/scripts/wasmd/stop.sh b/scripts/wasmd/stop.sh
new file mode 100755
index 0000000000..a318ce454f
--- /dev/null
+++ b/scripts/wasmd/stop.sh
@@ -0,0 +1,11 @@
+#!/bin/bash
+set -o errexit -o nounset -o pipefail
+command -v shellcheck > /dev/null && shellcheck "$0"
+
+SCRIPT_DIR="$(realpath "$(dirname "$0")")"
+# shellcheck source=./env
+# shellcheck disable=SC1091
+source "$SCRIPT_DIR"/env
+
+echo "Killing Cosmos container..."
+docker container kill "$CONTAINER_NAME"