movehat 0.0.6-alpha.0 → 0.0.8-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,18 +3,28 @@ dotenv.config();
3
3
 
4
4
  export default {
5
5
  // Default network to use when no --network flag is provided
6
+ // "testnet" = Movement testnet (public, auto-generates test accounts)
7
+ // "mainnet" = Movement mainnet (requires PRIVATE_KEY in .env)
8
+ // "local" = Fork server running on localhost:8080
6
9
  defaultNetwork: "testnet",
7
10
 
8
11
  // Network configurations
9
12
  networks: {
13
+ // Movement Testnet - Public test network (recommended for development)
14
+ // Auto-generates test accounts - no local setup required
15
+ // Perfect for running tests with transaction simulation
10
16
  testnet: {
11
17
  url: process.env.MOVEMENT_RPC_URL || "https://testnet.movementnetwork.xyz/v1",
12
18
  chainId: "testnet",
13
19
  },
20
+ // Movement Mainnet - Production network
21
+ // REQUIRES PRIVATE_KEY in .env - uses real MOVE tokens
14
22
  mainnet: {
15
23
  url: "https://mainnet.movementnetwork.xyz/v1",
16
24
  chainId: "mainnet",
17
25
  },
26
+ // Local fork server (requires: movehat fork serve)
27
+ // Useful for testing against a snapshot of real network state
18
28
  local: {
19
29
  url: "http://localhost:8080/v1",
20
30
  chainId: "local",
@@ -8,7 +8,7 @@
8
8
  "deploy": "movehat run scripts/deploy-counter.ts"
9
9
  },
10
10
  "dependencies": {
11
- "movehat": "^0.0.6-alpha.0",
11
+ "movehat": "latest",
12
12
  "@aptos-labs/ts-sdk": "^5.1.5",
13
13
  "dotenv": "^17.2.3"
14
14
  },
@@ -1,75 +1,72 @@
1
- import { describe, it, before, after } from "mocha";
1
+ // @ts-nocheck - This is a template file, dependencies are installed in user projects
2
+ import { describe, it, before } from "mocha";
2
3
  import { expect } from "chai";
3
4
  import { getMovehat, type MovehatRuntime } from "movehat";
4
- import type { MoveContract } from "movehat/helpers";
5
- import { assertTransactionSuccess, snapshot } from "movehat/helpers";
6
5
 
7
6
  describe("Counter Contract", () => {
8
7
  let mh: MovehatRuntime;
9
- let counter: MoveContract;
8
+ let contractAddress: string;
10
9
 
11
10
  before(async function () {
12
11
  this.timeout(30000);
13
12
 
14
13
  // Initialize Movehat Runtime Environment
14
+ // Uses testnet by default - no local setup required
15
15
  mh = await getMovehat();
16
16
 
17
- console.log(`\n✅ Testing on ${mh.network.name}`);
18
- console.log(` Account: ${mh.account.accountAddress.toString()}\n`);
17
+ contractAddress = mh.account.accountAddress.toString();
19
18
 
20
- // Get counter contract instance
21
- counter = mh.getContract(
22
- mh.account.accountAddress.toString(),
23
- "counter"
24
- );
19
+ console.log(`\nTesting on ${mh.network.name}`);
20
+ console.log(`Account: ${contractAddress}\n`);
25
21
  });
26
22
 
27
23
  describe("Counter functionality", () => {
28
- it("should initialize counter", async function () {
24
+ it("should initialize counter using simulation", async function () {
29
25
  this.timeout(30000);
30
26
 
31
- const txResult = await counter.call(mh.account, "init", []);
32
- assertTransactionSuccess(txResult);
33
-
34
- const value = await counter.view<number>("get", [
35
- mh.account.accountAddress.toString()
36
- ]);
37
-
38
- expect(value).to.equal(0);
39
- console.log(` ✓ Counter initialized with value: ${value}`);
27
+ // Build transaction
28
+ const transaction = await mh.aptos.transaction.build.simple({
29
+ sender: mh.account.accountAddress,
30
+ data: {
31
+ function: `${contractAddress}::counter::init`,
32
+ functionArguments: []
33
+ }
34
+ });
35
+
36
+ // Simulate transaction (no gas cost, instant)
37
+ const [simulation] = await mh.aptos.transaction.simulate.simple({
38
+ signerPublicKey: mh.account.publicKey,
39
+ transaction
40
+ });
41
+
42
+ // Verify simulation succeeded
43
+ expect(simulation.success).to.be.true;
44
+ console.log(`Counter init simulated successfully`);
45
+ console.log(`Gas used: ${simulation.gas_used}`);
40
46
  });
41
47
 
42
- it("should increment counter", async function () {
48
+ it("should increment counter using simulation", async function () {
43
49
  this.timeout(30000);
44
50
 
45
- const initialValue = await counter.view<number>("get", [
46
- mh.account.accountAddress.toString()
47
- ]);
48
-
49
- const txResult = await counter.call(mh.account, "increment", []);
50
- assertTransactionSuccess(txResult);
51
-
52
- const newValue = await counter.view<number>("get", [
53
- mh.account.accountAddress.toString()
54
- ]);
55
-
56
- expect(newValue).to.equal(initialValue + 1);
57
- console.log(` ✓ Counter incremented: ${initialValue} → ${newValue}`);
51
+ // Build increment transaction
52
+ const transaction = await mh.aptos.transaction.build.simple({
53
+ sender: mh.account.accountAddress,
54
+ data: {
55
+ function: `${contractAddress}::counter::increment`,
56
+ functionArguments: []
57
+ }
58
+ });
59
+
60
+ // Simulate transaction
61
+ const [simulation] = await mh.aptos.transaction.simulate.simple({
62
+ signerPublicKey: mh.account.publicKey,
63
+ transaction
64
+ });
65
+
66
+ // Verify simulation succeeded
67
+ expect(simulation.success).to.be.true;
68
+ console.log(`Counter increment simulated successfully`);
69
+ console.log(`Gas used: ${simulation.gas_used}`);
58
70
  });
59
71
  });
60
-
61
- // Optional: Create a snapshot after tests for debugging
62
- // Uncomment to enable
63
- /*
64
- after(async function () {
65
- this.timeout(30000);
66
-
67
- const snapshotPath = await snapshot({
68
- name: 'counter-test-final'
69
- });
70
-
71
- console.log(`\n📸 Snapshot created: ${snapshotPath}`);
72
- console.log(` Use 'aptos move sim view-resource --session ${snapshotPath}' to inspect state\n`);
73
- });
74
- */
75
72
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "movehat",
3
- "version": "0.0.6-alpha.0",
3
+ "version": "0.0.8-alpha.0",
4
4
  "type": "module",
5
5
  "description": "Hardhat-like development framework for Movement L1 and Aptos Move smart contracts",
6
6
  "bin": {
@@ -4,6 +4,72 @@ import { exec } from "child_process";
4
4
  import { loadUserConfig } from "../core/config.js";
5
5
  import { validateAndEscapePath, escapeShellArg } from "../core/shell.js";
6
6
 
7
+ /**
8
+ * Recursively find all .move files in a directory
9
+ * @param dir - Directory to search
10
+ * @param maxDepth - Maximum recursion depth (default: 10)
11
+ * @param currentDepth - Current recursion depth (internal use)
12
+ */
13
+ function findMoveFiles(dir: string, maxDepth: number = 10, currentDepth: number = 0): string[] {
14
+ const files: string[] = [];
15
+
16
+ // Prevent infinite loops from excessive recursion
17
+ if (currentDepth > maxDepth) {
18
+ return files;
19
+ }
20
+
21
+ const entries = fs.readdirSync(dir, { withFileTypes: true });
22
+
23
+ for (const entry of entries) {
24
+ const fullPath = path.join(dir, entry.name);
25
+
26
+ if (entry.isDirectory()) {
27
+ // Skip symlinks to prevent directory traversal and infinite loops
28
+ if (entry.isSymbolicLink()) {
29
+ continue;
30
+ }
31
+ files.push(...findMoveFiles(fullPath, maxDepth, currentDepth + 1));
32
+ } else if (entry.name.endsWith('.move')) {
33
+ files.push(fullPath);
34
+ }
35
+ }
36
+
37
+ return files;
38
+ }
39
+
40
+ /**
41
+ * Extract named addresses used in Move files
42
+ * Looks for patterns like: module <address>::<module_name>
43
+ */
44
+ function extractNamedAddresses(moveDir: string): Set<string> {
45
+ const addresses = new Set<string>();
46
+ const moveFiles = findMoveFiles(moveDir);
47
+
48
+ for (const file of moveFiles) {
49
+ let content = fs.readFileSync(file, 'utf-8');
50
+
51
+ // Strip comments to avoid false positives
52
+ // Remove block comments /* ... */ (non-greedy, handles newlines)
53
+ content = content.replace(/\/\*[\s\S]*?\*\//g, ' ');
54
+ // Remove line comments // ... to end of line
55
+ content = content.replace(/\/\/.*$/gm, ' ');
56
+
57
+ // Match: module <address>::<module_name>
58
+ const moduleRegex = /module\s+([a-zA-Z_][a-zA-Z0-9_]*)::/g;
59
+ let match;
60
+
61
+ while ((match = moduleRegex.exec(content)) !== null) {
62
+ const address = match[1];
63
+ // Skip standard addresses
64
+ if (address !== 'std' && address !== 'aptos_framework' && address !== 'aptos_std') {
65
+ addresses.add(address);
66
+ }
67
+ }
68
+ }
69
+
70
+ return addresses;
71
+ }
72
+
7
73
  function run(command: string, cwd: string) {
8
74
  return new Promise<void>((resolve, reject) => {
9
75
  exec(command, { cwd }, (error, stdout, stderr) => {
@@ -23,11 +89,11 @@ export default async function compileCommand() {
23
89
  // Compile is network-independent - only uses global config
24
90
  const userConfig = await loadUserConfig();
25
91
 
26
- console.log("📦 Compiling Move contracts (network-independent)...");
92
+ console.log("Compiling Move contracts...");
27
93
 
28
94
  const moveDir = path.resolve(process.cwd(), userConfig.moveDir || "./move");
29
95
  if (!fs.existsSync(moveDir)) {
30
- console.error(`❌ Move directory not found: ${moveDir}`);
96
+ console.error(`Move directory not found: ${moveDir}`);
31
97
  console.error(` Update movehat.config.ts -> moveDir`);
32
98
  return;
33
99
  }
@@ -35,8 +101,21 @@ export default async function compileCommand() {
35
101
  // Validate and escape to prevent command injection
36
102
  const safeMoveDir = validateAndEscapePath(moveDir, "Move directory");
37
103
 
38
- // Use global named addresses for compilation
39
- const namedAddresses = userConfig.namedAddresses ?? {};
104
+ // Auto-detect named addresses from Move files
105
+ const detectedAddresses = extractNamedAddresses(moveDir);
106
+
107
+ // Merge user-configured addresses with auto-detected ones
108
+ const namedAddresses = { ...(userConfig.namedAddresses ?? {}) };
109
+ const autoAssignedAddresses: string[] = [];
110
+
111
+ // For any detected address not in config, use a dev address
112
+ for (const addr of detectedAddresses) {
113
+ if (!namedAddresses[addr]) {
114
+ namedAddresses[addr] = "0xcafe"; // Dev address for compilation
115
+ autoAssignedAddresses.push(addr);
116
+ }
117
+ }
118
+
40
119
  let namedAddressesArg = "";
41
120
 
42
121
  if (Object.keys(namedAddresses).length > 0) {
@@ -70,15 +149,21 @@ export default async function compileCommand() {
70
149
  const command = `movement move build --package-dir ${safeMoveDir} ${namedAddressesArg}`.trim();
71
150
 
72
151
  console.log(` Move directory: ${moveDir}`);
73
- if (Object.keys(namedAddresses).length > 0) {
74
- console.log(` Named addresses: ${Object.keys(namedAddresses).join(", ")}`);
152
+ if (detectedAddresses.size > 0) {
153
+ console.log(` Detected addresses: ${Array.from(detectedAddresses).join(", ")}`);
154
+ }
155
+ if (Object.keys(userConfig.namedAddresses ?? {}).length > 0) {
156
+ console.log(` Configured addresses: ${Object.keys(userConfig.namedAddresses!).join(", ")}`);
157
+ }
158
+ if (autoAssignedAddresses.length > 0) {
159
+ console.log(` Auto-assigned dev address (0xcafe): ${autoAssignedAddresses.join(", ")}`);
75
160
  }
76
161
  console.log();
77
162
 
78
163
  await run(command, moveDir);
79
- console.log("Compilation finished successfully.");
164
+ console.log("Compilation finished successfully.");
80
165
  } catch (err: any) {
81
- console.error("Compilation failed:", err.message ?? err);
166
+ console.error("Compilation failed:", err.message ?? err);
82
167
  process.exit(1);
83
168
  }
84
169
  }
@@ -22,7 +22,7 @@ export default async function initCommand(projectName?: string) {
22
22
 
23
23
  // If the user cancels (Ctrl+C), exit
24
24
  if (!response.projectName) {
25
- console.log('\n❌ Project initialization cancelled.');
25
+ console.log('\nProject initialization cancelled.');
26
26
  process.exit(0);
27
27
  }
28
28
 
@@ -39,7 +39,7 @@ export default async function initCommand(projectName?: string) {
39
39
 
40
40
  const templatesDir = path.join(__dirname, "..", "templates");
41
41
 
42
- console.log("📁 Creating project structure...");
42
+ console.log("Creating project structure...");
43
43
 
44
44
  await copyFile(
45
45
  path.join(templatesDir, "package.json"),
@@ -79,7 +79,7 @@ export default async function initCommand(projectName?: string) {
79
79
  );
80
80
 
81
81
  // 3. Copiar carpeta move/
82
- console.log("📦 Setting up Move project...");
82
+ console.log("Setting up Move project...");
83
83
  await copyDir(
84
84
  path.join(templatesDir, "move"),
85
85
  path.join(projectPath, "move"),
@@ -87,21 +87,21 @@ export default async function initCommand(projectName?: string) {
87
87
  );
88
88
 
89
89
  // 4. Copiar scripts/
90
- console.log("📜 Adding deployment scripts...");
90
+ console.log("Adding deployment scripts...");
91
91
  await copyDir(
92
92
  path.join(templatesDir, "scripts"),
93
93
  path.join(projectPath, "scripts")
94
94
  );
95
95
 
96
96
  // 5. Copiar tests/
97
- console.log("🧪 Adding test files...");
97
+ console.log("Adding test files...");
98
98
  await copyDir(
99
99
  path.join(templatesDir, "tests"),
100
100
  path.join(projectPath, "tests")
101
101
  );
102
102
 
103
- console.log("\n✅ Project created successfully!\n");
104
- console.log("📝 Next steps:\n");
103
+ console.log("\nProject created successfully!\n");
104
+ console.log("Next steps:\n");
105
105
  console.log(` cd ${projectName}`);
106
106
  console.log(` cp .env.example .env`);
107
107
  console.log(` # Edit .env with your credentials`);
@@ -6,18 +6,18 @@ export default async function testCommand() {
6
6
  const testDir = join(process.cwd(), "tests");
7
7
 
8
8
  if (!existsSync(testDir)) {
9
- console.error("No tests directory found.");
9
+ console.error("No tests directory found.");
10
10
  console.error(" Create a 'tests' directory with your TypeScript test files.");
11
11
  process.exit(1);
12
12
  }
13
13
 
14
- console.log("🧪 Running TypeScript tests with Mocha...\n");
14
+ console.log("Running TypeScript tests with Mocha...\n");
15
15
 
16
16
  // Find mocha from project's node_modules
17
17
  const mochaPath = join(process.cwd(), "node_modules", ".bin", "mocha");
18
18
 
19
19
  if (!existsSync(mochaPath)) {
20
- console.error("Mocha not found in project dependencies.");
20
+ console.error("Mocha not found in project dependencies.");
21
21
  console.error(" Install it with: npm install --save-dev mocha");
22
22
  process.exit(1);
23
23
  }
@@ -36,7 +36,7 @@ export default async function testCommand() {
36
36
  });
37
37
 
38
38
  child.on("error", (error) => {
39
- console.error(`❌ Failed to run tests: ${error.message}`);
39
+ console.error(`Failed to run tests: ${error.message}`);
40
40
  process.exit(1);
41
41
  });
42
42
  }
@@ -78,6 +78,7 @@ export async function resolveNetworkConfig(
78
78
  networkName?: string
79
79
  ): Promise<MovehatConfig> {
80
80
  // Determine which network to use
81
+ // Default to "testnet" for testing with simulation
81
82
  const selectedNetwork =
82
83
  networkName ||
83
84
  process.env.MH_CLI_NETWORK ||
@@ -86,11 +87,31 @@ export async function resolveNetworkConfig(
86
87
  "testnet";
87
88
 
88
89
  // Check if network exists in config
89
- const networkConfig = userConfig.networks[selectedNetwork];
90
+ let networkConfig = userConfig.networks[selectedNetwork];
91
+
92
+ // Special case: Auto-generate config for testnet (public test network)
93
+ // This provides a better dev experience - no local setup required
94
+ if (!networkConfig && selectedNetwork === "testnet") {
95
+ networkConfig = {
96
+ url: "https://testnet.movementnetwork.xyz/v1",
97
+ chainId: "testnet",
98
+ };
99
+ console.log(`testnet not found in config - using default Movement testnet configuration`);
100
+ }
101
+
102
+ // Special case: Auto-generate config for local fork server
103
+ if (!networkConfig && selectedNetwork === "local") {
104
+ networkConfig = {
105
+ url: "http://localhost:8080/v1",
106
+ chainId: "local",
107
+ };
108
+ console.log(`Local network not found in config - using default fork server configuration`);
109
+ }
110
+
90
111
  if (!networkConfig) {
91
112
  const availableNetworks = Object.keys(userConfig.networks).join(", ");
92
113
  throw new Error(
93
- `Network '${selectedNetwork}' not found in configuration.\nAvailable networks: ${availableNetworks}`
114
+ `Network '${selectedNetwork}' not found in configuration.\nAvailable networks: ${availableNetworks}, testnet (auto-generated), local (auto-generated)`
94
115
  );
95
116
  }
96
117
 
@@ -117,15 +138,38 @@ export async function resolveNetworkConfig(
117
138
  accounts = [process.env.PRIVATE_KEY];
118
139
  }
119
140
 
120
- // 4. Validate we have at least one account
141
+ // 4. Validate we have at least one account (unless using testnet/local)
121
142
  if (accounts.length === 0 || !accounts[0]) {
122
- throw new Error(
123
- `Network '${selectedNetwork}' has no accounts configured.\n` +
124
- `Options:\n` +
125
- ` 1. Set PRIVATE_KEY in your .env file (recommended)\n` +
126
- ` 2. Add 'accounts: ["0x..."]' globally in movehat.config.ts\n` +
127
- ` 3. Add 'accounts: ["0x..."]' to the '${selectedNetwork}' network config`
128
- );
143
+ // Special case: Auto-generate test accounts for testing networks
144
+ // testnet = public Movement test network (recommended)
145
+ // local = local fork server
146
+ if (selectedNetwork === "testnet" || selectedNetwork === "local") {
147
+ // Security: Using a deterministic test account (like Hardhat's default accounts)
148
+ // This is SAFE because:
149
+ // 1. Only used for testnet/local (never mainnet - that throws error below)
150
+ // 2. Perfect for transaction simulation (no real funds)
151
+ // 3. Deterministic = consistent test results
152
+ const testPrivateKey = "0x0000000000000000000000000000000000000000000000000000000000000001";
153
+ accounts = [testPrivateKey];
154
+ console.log(`\n[TESTNET] Using auto-generated test account (safe for testing only)`);
155
+ console.log(`[TESTNET] For mainnet, set PRIVATE_KEY in .env\n`);
156
+ } else {
157
+ // For any other network (especially mainnet), REQUIRE explicit configuration
158
+ // This prevents accidentally using the test key on production networks
159
+ throw new Error(
160
+ `Network '${selectedNetwork}' has no accounts configured.\n` +
161
+ `\n` +
162
+ `SECURITY: This network requires explicit account configuration.\n` +
163
+ `\n` +
164
+ `Options:\n` +
165
+ ` 1. Set PRIVATE_KEY in your .env file (recommended for ${selectedNetwork})\n` +
166
+ ` 2. Add 'accounts: ["0x..."]' globally in movehat.config.ts\n` +
167
+ ` 3. Add 'accounts: ["0x..."]' to the '${selectedNetwork}' network config\n` +
168
+ `\n` +
169
+ `For testing without configuration, use:\n` +
170
+ ` movehat <command> --network testnet (auto-generates safe test accounts)`
171
+ );
172
+ }
129
173
  }
130
174
 
131
175
  // Merge named addresses (network-specific overrides global)
@@ -1,11 +1,18 @@
1
- # {{PROJECT_NAME}}
1
+ # {{projectName}}
2
2
 
3
3
  A Move smart contract project built with Movehat.
4
4
 
5
5
  ## Prerequisites
6
6
 
7
- - Node.js v18+
8
- - [Movement CLI](https://docs.movementnetwork.xyz/devs/movementCLI)
7
+ **Required:**
8
+ - **Node.js v18+** - [Download](https://nodejs.org/)
9
+ - **Movement CLI** - **REQUIRED** for compiling contracts
10
+
11
+ Install: [Movement CLI Installation Guide](https://docs.movementnetwork.xyz/devs/movementCLI)
12
+
13
+ Verify: `movement --version`
14
+
15
+ **⚠️ Important:** Without Movement CLI, compilation will fail!
9
16
 
10
17
  ## Getting Started
11
18
 
@@ -25,41 +32,36 @@ cp .env.example .env
25
32
 
26
33
  Edit `.env`:
27
34
  ```
28
- MH_PRIVATE_KEY=your_private_key_here
29
- MH_ACCOUNT=your_account_address_here
30
- MH_NETWORK=testnet
31
- ```
32
-
33
- ### 3. Update Move.toml
34
-
35
- Edit `move/Move.toml` and set the `counter` address to your account address:
36
-
37
- ```toml
38
- [addresses]
39
- counter = "0xYOUR_ACCOUNT_ADDRESS"
35
+ PRIVATE_KEY=your_private_key_here
40
36
  ```
41
37
 
42
- ### 4. Compile contracts
38
+ ### 3. Compile contracts
43
39
 
44
40
  ```bash
45
41
  npm run compile
46
42
  ```
47
43
 
48
- ### 5. Deploy
44
+ **How it works:**
45
+ - Movehat automatically detects named addresses from your Move files
46
+ - No need to manually configure addresses in `Move.toml`
47
+ - Just add any new `.move` file and it will compile automatically (like Hardhat!)
49
48
 
50
- ```bash
51
- npx tsx scripts/deploy-counter.ts
52
- ```
49
+ ### 4. Run tests
53
50
 
54
- Or use the Movement CLI directly:
55
51
  ```bash
56
- movement move publish --package-dir ./move --profile default --assume-yes
52
+ npm test
57
53
  ```
58
54
 
59
- ### 6. Run tests
55
+ **How it works:**
56
+ - Tests use **Transaction Simulation** - no real blockchain required
57
+ - Runs instantly without gas costs
58
+ - Uses Movement testnet by default with auto-generated test accounts
59
+ - Perfect for TDD and CI/CD workflows
60
+
61
+ ### 5. Deploy (optional)
60
62
 
61
63
  ```bash
62
- npm test
64
+ npx movehat run scripts/deploy-counter.ts
63
65
  ```
64
66
 
65
67
  ## Project Structure
@@ -80,10 +82,37 @@ npm test
80
82
 
81
83
  ## Available Commands
82
84
 
83
- - `npm run compile` - Compile Move contracts
85
+ - `npm run compile` - Compile Move contracts (auto-detects addresses)
84
86
  - `npm test` - Run integration tests
85
87
  - `npm run test:watch` - Run tests in watch mode
86
- - `npx tsx scripts/deploy-counter.ts` - Deploy and initialize counter
88
+ - `npx movehat run scripts/deploy-counter.ts` - Deploy and initialize counter
89
+
90
+ ## How Named Addresses Work
91
+
92
+ Movehat automatically detects named addresses from your Move code:
93
+
94
+ ```move
95
+ module counter::counter { // ← "counter" is auto-detected
96
+ // ...
97
+ }
98
+ ```
99
+
100
+ - **For development:** Movehat uses temp addresses (`0xcafe`) automatically
101
+ - **For production:** Specify real addresses in `movehat.config.ts`
102
+
103
+ **Adding new contracts:**
104
+ 1. Create `move/sources/MyContract.move`
105
+ 2. Write: `module mycontract::mycontract { ... }`
106
+ 3. Run `npm run compile`
107
+ 4. It just works! (like Hardhat)
108
+
109
+ ## Troubleshooting
110
+
111
+ | Error | Solution |
112
+ |-------|----------|
113
+ | `movement: command not found` | Install Movement CLI (see Prerequisites) |
114
+ | `Cannot find package 'dotenv'` | Run `npm install` |
115
+ | Compilation failed | Ensure Movement CLI is installed: `movement --version` |
87
116
 
88
117
  ## Learn More
89
118
 
@@ -7,6 +7,8 @@ authors = []
7
7
  counter = "_"
8
8
 
9
9
  [dev-addresses]
10
+ # Dev addresses are auto-detected by movehat during compilation
11
+ # You can also add them manually here if needed
10
12
 
11
13
  [dependencies.AptosFramework]
12
14
  git = "https://github.com/movementlabsxyz/aptos-core.git"
@@ -3,18 +3,28 @@ dotenv.config();
3
3
 
4
4
  export default {
5
5
  // Default network to use when no --network flag is provided
6
+ // "testnet" = Movement testnet (public, auto-generates test accounts)
7
+ // "mainnet" = Movement mainnet (requires PRIVATE_KEY in .env)
8
+ // "local" = Fork server running on localhost:8080
6
9
  defaultNetwork: "testnet",
7
10
 
8
11
  // Network configurations
9
12
  networks: {
13
+ // Movement Testnet - Public test network (recommended for development)
14
+ // Auto-generates test accounts - no local setup required
15
+ // Perfect for running tests with transaction simulation
10
16
  testnet: {
11
17
  url: process.env.MOVEMENT_RPC_URL || "https://testnet.movementnetwork.xyz/v1",
12
18
  chainId: "testnet",
13
19
  },
20
+ // Movement Mainnet - Production network
21
+ // REQUIRES PRIVATE_KEY in .env - uses real MOVE tokens
14
22
  mainnet: {
15
23
  url: "https://mainnet.movementnetwork.xyz/v1",
16
24
  chainId: "mainnet",
17
25
  },
26
+ // Local fork server (requires: movehat fork serve)
27
+ // Useful for testing against a snapshot of real network state
18
28
  local: {
19
29
  url: "http://localhost:8080/v1",
20
30
  chainId: "local",
@@ -8,7 +8,7 @@
8
8
  "deploy": "movehat run scripts/deploy-counter.ts"
9
9
  },
10
10
  "dependencies": {
11
- "movehat": "^0.0.6-alpha.0",
11
+ "movehat": "latest",
12
12
  "@aptos-labs/ts-sdk": "^5.1.5",
13
13
  "dotenv": "^17.2.3"
14
14
  },