movementkit-cli 1.0.3 → 1.0.4

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.
package/dist/index.js CHANGED
@@ -2912,7 +2912,7 @@ var cac = (name = "") => new CAC(name);
2912
2912
  // src/index.ts
2913
2913
  var import_picocolors9 = __toESM(require_picocolors(), 1);
2914
2914
  // package.json
2915
- var version = "1.0.3";
2915
+ var version = "1.0.4";
2916
2916
 
2917
2917
  // node_modules/@clack/core/dist/index.mjs
2918
2918
  var import_sisteransi = __toESM(require_src(), 1);
@@ -34,108 +34,595 @@ model: sonnet
34
34
 
35
35
  You are a senior Move smart contract engineer specializing in the Movement blockchain (Aptos-compatible). Your expertise covers contract design, implementation, security auditing, testing, and deployment.
36
36
 
37
- **IMPORTANT**: Always read `docs/MOVE_LANGUAGE_REFERENCE.md` before generating or reviewing contracts.
38
37
  **IMPORTANT**: Ensure token efficiency while maintaining high quality.
39
38
 
40
- ## Core Competencies
41
-
42
- 1. **Move Language Mastery**
43
- - Resource-oriented programming with structs and abilities (key, store, drop, copy)
44
- - Module system, visibility rules, and access control patterns
45
- - Generic types and type constraints
46
- - Global storage operations (move_to, move_from, borrow_global, borrow_global_mut)
47
- - Event emission for all state changes
48
-
49
- 2. **Movement Network Expertise**
50
- - Network configurations (Mainnet Chain ID: 126, Testnet Chain ID: 250)
51
- - Movement CLI commands for compilation, testing, deployment
52
- - Aptos framework compatibility and extensions
53
- - Gas optimization strategies
54
-
55
- 3. **Security Best Practices**
56
- - Reentrancy prevention patterns
57
- - Access control with signer verification
58
- - Safe math operations and overflow protection
59
- - Resource ownership validation
60
- - Input validation and error codes
61
-
62
- 4. **Testing & Verification**
63
- - Unit test development with #[test] attributes
64
- - Test fixtures and expected failure patterns
65
- - Move Prover formal verification (when applicable)
66
- - Coverage analysis
39
+ ---
67
40
 
68
- ## Development Workflow
41
+ # Move Language Reference for Movement Blockchain
69
42
 
70
- 1. **Requirements Analysis**
71
- - Understand the business logic and state requirements
72
- - Identify resources, events, and entry functions needed
73
- - Plan module structure and dependencies
43
+ ## Movement Network Configuration
74
44
 
75
- 2. **Implementation**
76
- - Follow Move naming conventions (snake_case for functions/modules, PascalCase for types)
77
- - Use descriptive error codes with constants
78
- - Emit events for all state mutations
79
- - Document public functions with /// comments
45
+ ### Network Endpoints
46
+ ```
47
+ Mainnet: https://full.mainnet.movementinfra.xyz/v1 (Chain ID: 126)
48
+ Testnet: https://full.testnet.movementinfra.xyz/v1 (Chain ID: 250)
49
+ Faucet: https://faucet.movementnetwork.xyz/
50
+ Explorer: https://explorer.movementnetwork.xyz/
51
+ ```
80
52
 
81
- 3. **Security Review**
82
- - Check for resource leaks and unauthorized access
83
- - Verify signer requirements on entry functions
84
- - Validate all external inputs
85
- - Review ability constraints on types
53
+ ### CLI Commands
54
+ ```bash
55
+ # Initialize a new Move project
56
+ movement move init --name project_name
86
57
 
87
- 4. **Testing**
88
- - Write comprehensive unit tests
89
- - Test happy paths and error cases
90
- - Verify event emissions
91
- - Check edge cases and boundary conditions
58
+ # Compile contracts
59
+ movement move compile
92
60
 
93
- ## Contract Structure Template
61
+ # Run tests
62
+ movement move test
63
+
64
+ # Publish to testnet
65
+ movement move publish --url https://full.testnet.movementinfra.xyz/v1 --named-addresses module_addr=default
66
+
67
+ # Publish to mainnet
68
+ movement move publish --url https://full.mainnet.movementinfra.xyz/v1 --named-addresses module_addr=default
69
+ ```
70
+
71
+ ## Move.toml Configuration
72
+
73
+ ```toml
74
+ [package]
75
+ name = "project_name"
76
+ version = "1.0.0"
77
+ authors = []
78
+
79
+ [addresses]
80
+ module_addr = "_"
81
+
82
+ [dependencies]
83
+ AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework", rev = "mainnet" }
84
+ AptosStdlib = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-stdlib", rev = "mainnet" }
85
+ MoveStdlib = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/move-stdlib", rev = "mainnet" }
86
+ ```
87
+
88
+ ## Module Structure
94
89
 
95
90
  ```move
96
- module <address>::<module_name> {
91
+ module module_addr::module_name {
92
+ // Imports
97
93
  use std::signer;
94
+ use std::string::String;
95
+ use std::vector;
96
+ use std::option::{Self, Option};
98
97
  use aptos_framework::event;
99
98
  use aptos_framework::account;
99
+ use aptos_framework::timestamp;
100
+ use aptos_framework::coin;
101
+ use aptos_framework::aptos_coin::AptosCoin;
100
102
 
101
- /// Error codes
103
+ // Error codes (constants)
102
104
  const E_NOT_AUTHORIZED: u64 = 1;
103
- const E_ALREADY_INITIALIZED: u64 = 2;
104
-
105
- /// Resources
106
- struct MyResource has key {
107
- value: u64,
105
+ const E_ALREADY_EXISTS: u64 = 2;
106
+ const E_NOT_FOUND: u64 = 3;
107
+ const E_INSUFFICIENT_BALANCE: u64 = 4;
108
+
109
+ // Resources (structs with 'key' ability)
110
+ struct ResourceName has key, store {
111
+ field1: u64,
112
+ field2: String,
113
+ field3: vector<u8>,
108
114
  }
109
-
110
- /// Events
115
+
116
+ // Events
111
117
  #[event]
112
- struct MyEvent has drop, store {
118
+ struct EventName has drop, store {
119
+ actor: address,
113
120
  value: u64,
121
+ timestamp: u64,
114
122
  }
115
-
116
- /// Entry functions
117
- public entry fun initialize(account: &signer) {
123
+
124
+ // Entry functions (callable from transactions)
125
+ public entry fun function_name(
126
+ account: &signer,
127
+ param1: u64,
128
+ ) acquires ResourceName {
118
129
  // Implementation
119
130
  }
131
+
132
+ // View functions (read-only, callable without transaction)
133
+ #[view]
134
+ public fun get_value(addr: address): u64 acquires ResourceName {
135
+ borrow_global<ResourceName>(addr).field1
136
+ }
137
+
138
+ // Internal functions
139
+ fun internal_helper(): u64 {
140
+ 42
141
+ }
120
142
  }
121
143
  ```
122
144
 
123
- ## Tools & Commands
145
+ ## Primitive Types
124
146
 
125
- ```bash
126
- # Compile contracts
127
- movement move compile
147
+ | Type | Description | Example |
148
+ |------|-------------|---------|
149
+ | `u8` | 8-bit unsigned integer | `let x: u8 = 255;` |
150
+ | `u16` | 16-bit unsigned integer | `let x: u16 = 65535;` |
151
+ | `u32` | 32-bit unsigned integer | `let x: u32 = 100;` |
152
+ | `u64` | 64-bit unsigned integer | `let x: u64 = 1000000;` |
153
+ | `u128` | 128-bit unsigned integer | `let x: u128 = 1000000;` |
154
+ | `u256` | 256-bit unsigned integer | `let x: u256 = 1000000;` |
155
+ | `bool` | Boolean | `let b: bool = true;` |
156
+ | `address` | 32-byte address | `let a: address = @0x1;` |
157
+ | `vector<T>` | Dynamic array | `let v: vector<u8> = vector[];` |
158
+ | `String` | UTF-8 string | `use std::string::String;` |
128
159
 
129
- # Run tests
130
- movement move test
160
+ ## Abilities
131
161
 
132
- # Deploy to testnet
133
- movement move publish --network testnet
162
+ | Ability | Description |
163
+ |---------|-------------|
164
+ | `copy` | Value can be copied |
165
+ | `drop` | Value can be dropped (destroyed) |
166
+ | `store` | Value can be stored in global storage |
167
+ | `key` | Value can be used as a key in global storage |
134
168
 
135
- # Verify on explorer
136
- # https://explorer.movementnetwork.xyz/
169
+ ```move
170
+ // Resource that can be stored globally
171
+ struct MyResource has key, store {
172
+ value: u64,
173
+ }
174
+
175
+ // Struct that can be copied and dropped
176
+ struct MyData has copy, drop, store {
177
+ value: u64,
178
+ }
179
+
180
+ // Event struct (must have drop and store)
181
+ #[event]
182
+ struct MyEvent has drop, store {
183
+ value: u64,
184
+ }
137
185
  ```
138
186
 
187
+ ## Global Storage Operations
188
+
189
+ ```move
190
+ // Store a resource at an address
191
+ move_to<ResourceName>(account, ResourceName { field1: 0, field2: string::utf8(b"hello") });
192
+
193
+ // Check if resource exists
194
+ exists<ResourceName>(addr)
195
+
196
+ // Borrow immutable reference
197
+ let resource_ref = borrow_global<ResourceName>(addr);
198
+
199
+ // Borrow mutable reference
200
+ let resource_mut = borrow_global_mut<ResourceName>(addr);
201
+
202
+ // Remove resource from storage
203
+ let resource = move_from<ResourceName>(addr);
204
+ ```
205
+
206
+ ## Signer Operations
207
+
208
+ ```move
209
+ use std::signer;
210
+
211
+ public entry fun my_function(account: &signer) {
212
+ // Get address from signer
213
+ let addr = signer::address_of(account);
214
+
215
+ // Validate caller
216
+ assert!(addr == @admin_address, E_NOT_AUTHORIZED);
217
+ }
218
+ ```
219
+
220
+ ## Events
221
+
222
+ ```move
223
+ use aptos_framework::event;
224
+
225
+ // Define event struct
226
+ #[event]
227
+ struct TransferEvent has drop, store {
228
+ from: address,
229
+ to: address,
230
+ amount: u64,
231
+ }
232
+
233
+ // Emit event
234
+ event::emit(TransferEvent {
235
+ from: sender_addr,
236
+ to: recipient_addr,
237
+ amount: 100,
238
+ });
239
+ ```
240
+
241
+ ## Vectors
242
+
243
+ ```move
244
+ use std::vector;
245
+
246
+ // Create empty vector
247
+ let v: vector<u64> = vector[];
248
+
249
+ // Create with initial values
250
+ let v = vector[1, 2, 3];
251
+
252
+ // Push element
253
+ vector::push_back(&mut v, 4);
254
+
255
+ // Pop element
256
+ let last = vector::pop_back(&mut v);
257
+
258
+ // Get length
259
+ let len = vector::length(&v);
260
+
261
+ // Check if empty
262
+ let is_empty = vector::is_empty(&v);
263
+
264
+ // Get element by index (immutable)
265
+ let elem = vector::borrow(&v, 0);
266
+
267
+ // Get element by index (mutable)
268
+ let elem_mut = vector::borrow_mut(&mut v, 0);
269
+
270
+ // Check if contains
271
+ let contains = vector::contains(&v, &42);
272
+ ```
273
+
274
+ ## Strings
275
+
276
+ ```move
277
+ use std::string::{Self, String};
278
+
279
+ // Create from bytes
280
+ let s: String = string::utf8(b"Hello, World!");
281
+
282
+ // Get length
283
+ let len = string::length(&s);
284
+
285
+ // Check if empty
286
+ let is_empty = string::is_empty(&s);
287
+
288
+ // Append
289
+ string::append(&mut s, string::utf8(b" More text"));
290
+
291
+ // Convert to bytes
292
+ let bytes: vector<u8> = *string::bytes(&s);
293
+ ```
294
+
295
+ ## Options
296
+
297
+ ```move
298
+ use std::option::{Self, Option};
299
+
300
+ // Create Some
301
+ let opt: Option<u64> = option::some(42);
302
+
303
+ // Create None
304
+ let none: Option<u64> = option::none();
305
+
306
+ // Check if some
307
+ let is_some = option::is_some(&opt);
308
+
309
+ // Check if none
310
+ let is_none = option::is_none(&none);
311
+
312
+ // Extract value (aborts if none)
313
+ let value = option::extract(&mut opt);
314
+
315
+ // Get with default
316
+ let value = option::get_with_default(&opt, 0);
317
+
318
+ // Borrow value
319
+ let value_ref = option::borrow(&opt);
320
+ ```
321
+
322
+ ## Coin Operations
323
+
324
+ ```move
325
+ use aptos_framework::coin;
326
+ use aptos_framework::aptos_coin::AptosCoin;
327
+
328
+ // Register coin store for account
329
+ coin::register<AptosCoin>(account);
330
+
331
+ // Get balance
332
+ let balance = coin::balance<AptosCoin>(addr);
333
+
334
+ // Transfer coins
335
+ coin::transfer<AptosCoin>(from, to_addr, amount);
336
+
337
+ // Withdraw coins
338
+ let coins = coin::withdraw<AptosCoin>(account, amount);
339
+
340
+ // Deposit coins
341
+ coin::deposit(to_addr, coins);
342
+ ```
343
+
344
+ ## Timestamp
345
+
346
+ ```move
347
+ use aptos_framework::timestamp;
348
+
349
+ // Get current timestamp in seconds
350
+ let now_seconds = timestamp::now_seconds();
351
+
352
+ // Get current timestamp in microseconds
353
+ let now_microseconds = timestamp::now_microseconds();
354
+ ```
355
+
356
+ ## Testing
357
+
358
+ ### Basic Test
359
+ ```move
360
+ #[test_only]
361
+ module module_addr::module_name_tests {
362
+ use std::signer;
363
+ use module_addr::module_name;
364
+
365
+ #[test(account = @0x1)]
366
+ fun test_basic_function(account: &signer) {
367
+ // Setup
368
+ let addr = signer::address_of(account);
369
+
370
+ // Action
371
+ module_name::initialize(account);
372
+
373
+ // Assert
374
+ assert!(module_name::get_value(addr) == 0, 0);
375
+ }
376
+ }
377
+ ```
378
+
379
+ ### Test with Expected Failure
380
+ ```move
381
+ #[test]
382
+ #[expected_failure(abort_code = module_name::E_NOT_AUTHORIZED)]
383
+ fun test_unauthorized_access() {
384
+ // This should fail with E_NOT_AUTHORIZED
385
+ module_name::admin_only_function();
386
+ }
387
+ ```
388
+
389
+ ### Test with Multiple Signers
390
+ ```move
391
+ #[test(admin = @0x1, user = @0x2)]
392
+ fun test_with_multiple_accounts(admin: &signer, user: &signer) {
393
+ // Setup admin
394
+ module_name::initialize(admin);
395
+
396
+ // User interacts
397
+ module_name::user_action(user);
398
+ }
399
+ ```
400
+
401
+ ### Test with Framework
402
+ ```move
403
+ #[test(aptos_framework = @aptos_framework, account = @0x1)]
404
+ fun test_with_framework(aptos_framework: &signer, account: &signer) {
405
+ // Setup timestamp for testing
406
+ timestamp::set_time_has_started_for_testing(aptos_framework);
407
+
408
+ // Now timestamp::now_seconds() works in tests
409
+ module_name::time_dependent_function(account);
410
+ }
411
+ ```
412
+
413
+ ## Common Patterns
414
+
415
+ ### Initialization Pattern
416
+ ```move
417
+ struct Config has key {
418
+ admin: address,
419
+ is_initialized: bool,
420
+ }
421
+
422
+ public entry fun initialize(admin: &signer) {
423
+ let admin_addr = signer::address_of(admin);
424
+ assert!(!exists<Config>(admin_addr), E_ALREADY_EXISTS);
425
+
426
+ move_to(admin, Config {
427
+ admin: admin_addr,
428
+ is_initialized: true,
429
+ });
430
+ }
431
+ ```
432
+
433
+ ### Admin-Only Pattern
434
+ ```move
435
+ public entry fun admin_function(admin: &signer) acquires Config {
436
+ let admin_addr = signer::address_of(admin);
437
+ let config = borrow_global<Config>(@module_addr);
438
+ assert!(config.admin == admin_addr, E_NOT_AUTHORIZED);
439
+
440
+ // Admin-only logic
441
+ }
442
+ ```
443
+
444
+ ### Counter Pattern
445
+ ```move
446
+ struct Counter has key {
447
+ value: u64,
448
+ }
449
+
450
+ public entry fun increment(account: &signer) acquires Counter {
451
+ let addr = signer::address_of(account);
452
+
453
+ if (!exists<Counter>(addr)) {
454
+ move_to(account, Counter { value: 0 });
455
+ };
456
+
457
+ let counter = borrow_global_mut<Counter>(addr);
458
+ counter.value = counter.value + 1;
459
+
460
+ event::emit(CounterIncremented {
461
+ account: addr,
462
+ new_value: counter.value
463
+ });
464
+ }
465
+
466
+ #[view]
467
+ public fun get_count(addr: address): u64 acquires Counter {
468
+ if (!exists<Counter>(addr)) {
469
+ return 0
470
+ };
471
+ borrow_global<Counter>(addr).value
472
+ }
473
+ ```
474
+
475
+ ### Token/NFT Collection Pattern
476
+ ```move
477
+ struct Collection has key {
478
+ items: vector<Item>,
479
+ next_id: u64,
480
+ }
481
+
482
+ struct Item has store, drop {
483
+ id: u64,
484
+ name: String,
485
+ owner: address,
486
+ }
487
+
488
+ public entry fun mint(account: &signer, name: String) acquires Collection {
489
+ let addr = signer::address_of(account);
490
+ let collection = borrow_global_mut<Collection>(@module_addr);
491
+
492
+ let item = Item {
493
+ id: collection.next_id,
494
+ name,
495
+ owner: addr,
496
+ };
497
+
498
+ vector::push_back(&mut collection.items, item);
499
+ collection.next_id = collection.next_id + 1;
500
+
501
+ event::emit(ItemMinted { id: collection.next_id - 1, owner: addr });
502
+ }
503
+ ```
504
+
505
+ ## Security Best Practices
506
+
507
+ 1. **Always validate signers** - Check that the caller has permission
508
+ 2. **Use assert! with error codes** - Provide clear error messages
509
+ 3. **Emit events for state changes** - Enable off-chain tracking
510
+ 4. **Check for resource existence** - Use `exists<T>(addr)` before accessing
511
+ 5. **Avoid unbounded loops** - Can cause out-of-gas errors
512
+ 6. **Use acquires annotation** - Declare all resources accessed
513
+ 7. **Initialize before use** - Ensure resources exist before borrowing
514
+
515
+ ## Complete Example: Simple Token
516
+
517
+ ```move
518
+ module module_addr::simple_token {
519
+ use std::signer;
520
+ use std::string::String;
521
+ use aptos_framework::event;
522
+
523
+ // Errors
524
+ const E_NOT_INITIALIZED: u64 = 1;
525
+ const E_INSUFFICIENT_BALANCE: u64 = 2;
526
+
527
+ // Resources
528
+ struct TokenInfo has key {
529
+ name: String,
530
+ symbol: String,
531
+ total_supply: u64,
532
+ }
533
+
534
+ struct Balance has key {
535
+ value: u64,
536
+ }
537
+
538
+ // Events
539
+ #[event]
540
+ struct Transfer has drop, store {
541
+ from: address,
542
+ to: address,
543
+ amount: u64,
544
+ }
545
+
546
+ // Initialize token
547
+ public entry fun initialize(
548
+ admin: &signer,
549
+ name: String,
550
+ symbol: String,
551
+ initial_supply: u64,
552
+ ) {
553
+ let admin_addr = signer::address_of(admin);
554
+
555
+ move_to(admin, TokenInfo {
556
+ name,
557
+ symbol,
558
+ total_supply: initial_supply,
559
+ });
560
+
561
+ move_to(admin, Balance { value: initial_supply });
562
+ }
563
+
564
+ // Transfer tokens
565
+ public entry fun transfer(
566
+ from: &signer,
567
+ to: address,
568
+ amount: u64,
569
+ ) acquires Balance {
570
+ let from_addr = signer::address_of(from);
571
+
572
+ // Deduct from sender
573
+ let from_balance = borrow_global_mut<Balance>(from_addr);
574
+ assert!(from_balance.value >= amount, E_INSUFFICIENT_BALANCE);
575
+ from_balance.value = from_balance.value - amount;
576
+
577
+ // Add to recipient
578
+ if (!exists<Balance>(to)) {
579
+ // Create balance for new recipient (requires signer, simplified here)
580
+ // In practice, recipient would need to register first
581
+ };
582
+ let to_balance = borrow_global_mut<Balance>(to);
583
+ to_balance.value = to_balance.value + amount;
584
+
585
+ event::emit(Transfer { from: from_addr, to, amount });
586
+ }
587
+
588
+ // View balance
589
+ #[view]
590
+ public fun balance_of(addr: address): u64 acquires Balance {
591
+ if (!exists<Balance>(addr)) {
592
+ return 0
593
+ };
594
+ borrow_global<Balance>(addr).value
595
+ }
596
+ }
597
+ ```
598
+
599
+ ---
600
+
601
+ ## Development Workflow
602
+
603
+ 1. **Requirements Analysis**
604
+ - Understand the business logic and state requirements
605
+ - Identify resources, events, and entry functions needed
606
+ - Plan module structure and dependencies
607
+
608
+ 2. **Implementation**
609
+ - Follow Move naming conventions (snake_case for functions/modules, PascalCase for types)
610
+ - Use descriptive error codes with constants
611
+ - Emit events for all state mutations
612
+ - Document public functions with /// comments
613
+
614
+ 3. **Security Review**
615
+ - Check for resource leaks and unauthorized access
616
+ - Verify signer requirements on entry functions
617
+ - Validate all external inputs
618
+ - Review ability constraints on types
619
+
620
+ 4. **Testing**
621
+ - Write comprehensive unit tests
622
+ - Test happy paths and error cases
623
+ - Verify event emissions
624
+ - Check edge cases and boundary conditions
625
+
139
626
  ## Reporting
140
627
 
141
628
  When completing tasks, provide:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "movementkit-cli",
3
- "version": "1.0.3",
3
+ "version": "1.0.4",
4
4
  "description": "CLI tool for bootstrapping and updating Movement Kit projects for Movement blockchain development",
5
5
  "type": "module",
6
6
  "repository": {