Skip to content
gilbertsahumadaPublic

About

Hardhat for Move Smart Contracts

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Latest commit

 

History

821 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Movehat

Movehat

A Hardhat-like development framework for Movement L1 smart contracts.

Write your tests and deployment scripts in TypeScript while building Move contracts.

NPM Version License

Full documentation


Features

  • Hardhat-style Harness API — Harness.createLocal, createFork, createLive factory methods with explicit lifecycle (cleanup()) and use-after-cleanup safety (Proxy poisoning).
  • Three execution modes — full local blockchain, read-only fork of a remote network, or live testnet/mainnet binding.
  • Auto-deploy in tests + auto-detect named addresses — contracts compile and deploy automatically; no manual address wiring.
  • Fast local boot with movelite — on supported platforms an auto-installed movelite binary boots the local test chain in under a second instead of ~15s, with transparent fallback to the full Movement node.
  • Foundry-style execution traces — raise verbosity (-vv … -vvvv) to render an indented call tree for each contract.call(...) with decoded arguments, gas, events, and the abort stack (full tree on the movelite backend; the Movement node renders a degraded flat trace — events, state changes, and gas).
  • Native fork system — local JSON-backed snapshots of Movement L1 state, no BCS compatibility issues.
  • TypeScript-first — single PRIVATE_KEY across all networks (Hardhat-style); deployments tracked per-network in deployments/.
  • SLSA-provenance releases — every npm release ships with Trusted Publishers provenance. Verify with npm view movehat@<version>.
  • Security hardening built-in — path-traversal, command-injection, and YAML-injection protections at every boundary.

Quick Start

Prerequisites

Installation

npm install -g movehat
# or
pnpm install -g movehat

Five commands to a working test

npx movehat init my-project    # 1. Scaffold project
cd my-project
npm install                    # 2. Install dependencies
npx movehat compile            # 3. Compile contracts (auto-detects addresses)
npm test                       # 4. Run tests (auto-starts local node, deploys, runs)

That's it — local blockchain starts automatically, accounts get funded, contracts deploy, tests run.

For more depth (project layout, configuration, account model, deployment tracking), browse the full docs.

Configuration

A minimal movehat.config.ts looks like this:

import dotenv from "dotenv";
dotenv.config();

export default {
  defaultNetwork: "local",
  networks: {
    testnet: { url: process.env.MOVEMENT_RPC_URL || "https://testnet.movementnetwork.xyz/v1", chainId: "testnet" },
    mainnet: { url: "https://mainnet.movementnetwork.xyz/v1", chainId: "mainnet" },
    local:   { url: "http://localhost:8080/v1", chainId: "local" },
  },
  accounts: process.env.PRIVATE_KEY ? [process.env.PRIVATE_KEY] : [],
  moveDir: "./move",
};

A single PRIVATE_KEY is reused across networks (Hardhat-style). For testing, accounts are auto-generated and funded from the local faucet — no .env needed.

Full reference: /docs/getting-started/configuration.

Writing Tests

The canonical pattern uses Harness.createLocal:

// tests/Counter.test.ts
import { describe, it, before, after } from "mocha";
import { expect } from "chai";
import { Harness } from "movehat";
import type { MoveContract } from "movehat/helpers";

describe("Counter Contract", () => {
  let harness: Harness;
  let counter: MoveContract;
  let counterAddr: string;

  before(async function () {
    this.timeout(60000); // Local node startup + autoDeploy

    harness = await Harness.createLocal({
      accountLabels: ["deployer", "alice"],
      autoDeploy: ["counter"],
    });

    counterAddr = harness.runtime.getDeploymentAddress("counter");
    counter = harness.runtime.getContract(counterAddr, "counter");
  });

  after(async () => { await harness.cleanup(); });

  it("alice can increment her own counter", async () => {
    const alice = harness.runtime.getAccountByLabel("alice");
    await counter.call(alice, "increment", []);
    const [value] = await harness.runViewFunction({
      function: `${counterAddr}::counter::get`,
      functionArguments: [alice.accountAddress.toString()],
    });
    expect(parseInt(value as string)).to.equal(1);
  });
});

Run with npm test (interactive menu) or movehat test --ts (TypeScript suite, starts local node).

setupTestFixture from movehat/helpers is a lighter-weight alternative for tests that don't need the Harness lifecycle — both styles are documented at /docs/guides/testing.

Writing Deployment Scripts

Deploy safely to a local chain by default, and opt into live networks explicitly:

// scripts/deploy-counter.ts
import { Harness } from "movehat";
import config from "../movehat.config.js";

async function main() {
  const network = process.env.MH_CLI_NETWORK
    ?? process.env.MOVEHAT_NETWORK
    ?? process.env.MH_DEFAULT_NETWORK
    ?? config.defaultNetwork
    ?? "local";
  const isLocal = network === "local" || network === "movelite";
  const harness = isLocal
    ? await Harness.createLocal({
        ...(network === "movelite" ? { useMovelite: true } : {}),
        autoDeploy: ["counter"],
      })
    : await Harness.createLive(network);
  try {
    const deployment = isLocal
      ? harness.runtime.getDeployment("counter")
      : await harness.deployCodeObject({ moduleName: "counter" });
    if (!deployment) throw new Error("Counter deployment was not created");
    console.log(`Deployed: ${deployment.address}::counter`);
    console.log(`Tx:       ${deployment.txHash}`);

    // Initialize the freshly deployed module
    const counter = harness.runtime.getContract(deployment.address, "counter");
    await counter.call(harness.runtime.account, "init", []);
  } finally {
    await harness.cleanup();
  }
}

main().catch((err) => { console.error(err); process.exit(1); });

Run locally with movehat run scripts/deploy-counter.ts, or target testnet explicitly with movehat run scripts/deploy-counter.ts --network testnet.

Live re-runs fail with ModuleAlreadyDeployedError (recorded at deployments/{network}/counter.json). Set MH_CLI_REDEPLOY=true to force a live re-deploy; the disposable local chain starts clean.

Requires movehat@^0.2.0. Full deploy guide (named addresses, code-object semantics, redeploy flow, deployment tracking): /docs/guides/deployment.

Fork System

Movehat ships a native fork system for testing against real Movement L1 state without deploying to testnet. Forks are JSON-backed local snapshots that lazy-load resources as you read them, and Harness.createFork(network) binds a Harness to one.

Full fork docs: FORK_GUIDE.md (in-repo, comprehensive) or /docs/guides/fork (live site).

CLI Reference

Command Description Docs
movehat init [name] Scaffold a new Movehat project /docs/cli/init
movehat compile Compile Move contracts via Movement CLI /docs/cli/compile
movehat lint Lint the configured Move package /docs/cli/lint-and-prove
movehat prove Run the Move Prover without an artificial timeout /docs/cli/lint-and-prove
movehat test --coverage Run covered Move tests and print their coverage summary /docs/cli/test
movehat test [--move|--ts|--all] Run Move and/or TypeScript tests (TTY menu; all suites in non-interactive use) /docs/cli/test
movehat run <script> Execute a TypeScript deployment / interaction script /docs/cli/run
movehat fork <subcmd> Manage local network forks (create / list / serve / fund / view-resource) /docs/cli/fork
movehat update Check npm for a newer version and upgrade —

--coverage by itself covers only the Move test phase. Combine it with --all to run covered Move tests and their summary before the TypeScript suite. Coverage cannot be combined with --watch; --coverage --ts is rejected unless --all is also present. --filter applies to the Move phase only.

Troubleshooting

Error Solution
movement: command not found Install Movement CLI per the Movement docs
Module "X" is already deployed on Y Set MH_CLI_REDEPLOY=true to force a re-deploy
Configuration file not found Create movehat.config.ts or run movehat init
No accounts configured Set PRIVATE_KEY in .env
Cannot find package 'dotenv' Run npm install or pnpm install in the project dir

For anything not on this list, open an issue on GitHub.

Contributing

See CONTRIBUTING.md for development setup, the dual-tier test infrastructure, and the PR workflow. See MAINTENANCE.md for release cadence, triage SLA, versioning, and deprecation policy.

License

MIT — see LICENSE.

Links

Author

Gilberts Ahumada

Twitter YouTube Website

About

Hardhat for Move Smart Contracts

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages