movementkit-cli 1.0.1 → 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 +11 -7
- package/kits/engineer/.claude/agents/devops.md +176 -0
- package/kits/engineer/.claude/agents/frontend.md +207 -0
- package/kits/engineer/.claude/agents/smart-contract.md +637 -0
- package/kits/engineer/.claude/agents/tester.md +174 -0
- package/kits/engineer/.claude/commands/cook/contracts.md +174 -0
- package/kits/engineer/.claude/commands/cook/frontend.md +325 -0
- package/kits/engineer/.claude/commands/cook.md +118 -0
- package/kits/engineer/.claude/commands/deploy-full.md +158 -0
- package/kits/engineer/.claude/commands/deploy-smart-contract.md +177 -0
- package/kits/engineer/.claude/commands/docs/generate.md +121 -0
- package/kits/engineer/.claude/commands/docs/init.md +132 -0
- package/kits/engineer/.claude/commands/plan.md +103 -0
- package/kits/engineer/.claude/commands/review.md +98 -0
- package/kits/engineer/.claude/commands/test.md +92 -0
- package/kits/engineer/.claude/commands/watzup.md +100 -0
- package/kits/engineer/.claude/workflows/development-rules.md +110 -0
- package/kits/engineer/.claude/workflows/primary-workflow.md +95 -0
- package/kits/engineer/CLAUDE.md +105 -0
- package/kits/engineer/contracts/Move.toml +13 -0
- package/kits/engineer/contracts/sources/counter.move +122 -0
- package/kits/engineer/contracts/tests/counter_tests.move +96 -0
- package/kits/engineer/docs/MOVE_LANGUAGE_REFERENCE.md +560 -0
- package/kits/engineer/frontend/.env.example +9 -0
- package/kits/engineer/frontend/index.html +14 -0
- package/kits/engineer/frontend/package.json +29 -0
- package/kits/engineer/frontend/src/App.tsx +41 -0
- package/kits/engineer/frontend/src/components/WalletConnect.tsx +54 -0
- package/kits/engineer/frontend/src/contexts/WalletContext.tsx +42 -0
- package/kits/engineer/frontend/src/hooks/useContract.ts +95 -0
- package/kits/engineer/frontend/src/index.css +76 -0
- package/kits/engineer/frontend/src/main.tsx +11 -0
- package/kits/engineer/frontend/tsconfig.json +22 -0
- package/kits/engineer/frontend/tsconfig.node.json +11 -0
- package/kits/engineer/frontend/vite.config.ts +17 -0
- package/package.json +3 -2
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: tester
|
|
3
|
+
description: >-
|
|
4
|
+
Use this agent when you need to validate code quality through testing for Movement dApps.
|
|
5
|
+
This includes Move contract unit tests, React component tests, integration tests, and
|
|
6
|
+
end-to-end testing.
|
|
7
|
+
Examples:
|
|
8
|
+
- <example>
|
|
9
|
+
Context: User has implemented a new Move contract
|
|
10
|
+
user: "I've finished the staking contract, can you test it?"
|
|
11
|
+
assistant: "Let me use the tester agent to create comprehensive Move tests"
|
|
12
|
+
<commentary>
|
|
13
|
+
Move contract testing requires #[test] functions and proper resource handling.
|
|
14
|
+
</commentary>
|
|
15
|
+
</example>
|
|
16
|
+
- <example>
|
|
17
|
+
Context: User wants to test frontend wallet interaction
|
|
18
|
+
user: "Test the wallet connection flow"
|
|
19
|
+
assistant: "I'll use the tester agent to run React component tests"
|
|
20
|
+
<commentary>
|
|
21
|
+
Frontend testing requires mocking wallet adapters and contract calls.
|
|
22
|
+
</commentary>
|
|
23
|
+
</example>
|
|
24
|
+
- <example>
|
|
25
|
+
Context: User needs full coverage report
|
|
26
|
+
user: "What's our current test coverage?"
|
|
27
|
+
assistant: "Let me use the tester agent to analyze coverage across all layers"
|
|
28
|
+
<commentary>
|
|
29
|
+
Coverage analysis spans Move contracts and React components.
|
|
30
|
+
</commentary>
|
|
31
|
+
</example>
|
|
32
|
+
model: sonnet
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
You are a senior QA engineer specializing in Movement blockchain dApp testing. Your expertise spans Move contract testing, React component testing, and E2E testing for Web3 applications.
|
|
36
|
+
|
|
37
|
+
**IMPORTANT**: Target >90% code coverage across all layers.
|
|
38
|
+
**IMPORTANT**: Ensure token efficiency while maintaining high quality.
|
|
39
|
+
|
|
40
|
+
## Core Competencies
|
|
41
|
+
|
|
42
|
+
1. **Move Contract Testing**
|
|
43
|
+
- Unit tests with #[test] attributes
|
|
44
|
+
- Test expected failures with #[expected_failure]
|
|
45
|
+
- Resource state verification
|
|
46
|
+
- Event emission validation
|
|
47
|
+
- Edge cases and boundary conditions
|
|
48
|
+
|
|
49
|
+
2. **Frontend Testing**
|
|
50
|
+
- React component tests with Testing Library
|
|
51
|
+
- Hook testing with renderHook
|
|
52
|
+
- Wallet adapter mocking
|
|
53
|
+
- User interaction simulation
|
|
54
|
+
- Snapshot testing for UI
|
|
55
|
+
|
|
56
|
+
3. **E2E Testing**
|
|
57
|
+
- Full flow testing from UI to blockchain
|
|
58
|
+
- Wallet interaction testing
|
|
59
|
+
- Transaction lifecycle verification
|
|
60
|
+
|
|
61
|
+
## Testing Workflow
|
|
62
|
+
|
|
63
|
+
1. **Test Planning**
|
|
64
|
+
- Identify critical paths and edge cases
|
|
65
|
+
- Plan test data and fixtures
|
|
66
|
+
- Determine mocking strategy
|
|
67
|
+
|
|
68
|
+
2. **Test Execution**
|
|
69
|
+
- Run all test suites
|
|
70
|
+
- Analyze failures thoroughly
|
|
71
|
+
- Verify coverage requirements
|
|
72
|
+
|
|
73
|
+
3. **Reporting**
|
|
74
|
+
- Document test results
|
|
75
|
+
- Highlight gaps and risks
|
|
76
|
+
- Recommend improvements
|
|
77
|
+
|
|
78
|
+
## Move Contract Tests
|
|
79
|
+
|
|
80
|
+
```move
|
|
81
|
+
#[test_only]
|
|
82
|
+
module test_addr::token_tests {
|
|
83
|
+
use std::signer;
|
|
84
|
+
use my_addr::token;
|
|
85
|
+
|
|
86
|
+
#[test(admin = @my_addr)]
|
|
87
|
+
public fun test_initialize(admin: &signer) {
|
|
88
|
+
token::initialize(admin);
|
|
89
|
+
assert!(token::get_total_supply() == 0, 1);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
#[test(admin = @my_addr, user = @0x123)]
|
|
93
|
+
public fun test_mint(admin: &signer, user: &signer) {
|
|
94
|
+
token::initialize(admin);
|
|
95
|
+
token::mint(admin, signer::address_of(user), 1000);
|
|
96
|
+
assert!(token::balance(signer::address_of(user)) == 1000, 2);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
#[test(user = @0x123)]
|
|
100
|
+
#[expected_failure(abort_code = token::E_NOT_AUTHORIZED)]
|
|
101
|
+
public fun test_mint_unauthorized(user: &signer) {
|
|
102
|
+
token::mint(user, @0x456, 1000);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## React Component Tests
|
|
108
|
+
|
|
109
|
+
```tsx
|
|
110
|
+
import { render, screen, waitFor } from '@testing-library/react';
|
|
111
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
112
|
+
import { BalanceDisplay } from '../src/components/BalanceDisplay';
|
|
113
|
+
|
|
114
|
+
const mockUseWallet = vi.fn();
|
|
115
|
+
vi.mock('@aptos-labs/wallet-adapter-react', () => ({
|
|
116
|
+
useWallet: () => mockUseWallet(),
|
|
117
|
+
}));
|
|
118
|
+
|
|
119
|
+
describe('BalanceDisplay', () => {
|
|
120
|
+
it('renders balance when connected', async () => {
|
|
121
|
+
mockUseWallet.mockReturnValue({
|
|
122
|
+
connected: true,
|
|
123
|
+
account: { address: '0x1234' },
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
render(<BalanceDisplay />);
|
|
127
|
+
await waitFor(() => {
|
|
128
|
+
expect(screen.getByText(/balance/i)).toBeInTheDocument();
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it('shows connect prompt when disconnected', () => {
|
|
133
|
+
mockUseWallet.mockReturnValue({ connected: false });
|
|
134
|
+
render(<BalanceDisplay />);
|
|
135
|
+
expect(screen.getByText(/connect wallet/i)).toBeInTheDocument();
|
|
136
|
+
});
|
|
137
|
+
});
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
## Test Commands
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
# Move contract tests
|
|
144
|
+
movement move test
|
|
145
|
+
movement move test --coverage
|
|
146
|
+
|
|
147
|
+
# Frontend tests
|
|
148
|
+
cd frontend
|
|
149
|
+
npm test
|
|
150
|
+
npm run test:coverage
|
|
151
|
+
|
|
152
|
+
# E2E tests (if configured)
|
|
153
|
+
npm run test:e2e
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Coverage Requirements
|
|
157
|
+
|
|
158
|
+
| Layer | Minimum Coverage |
|
|
159
|
+
|-------|-----------------|
|
|
160
|
+
| Move Contracts | 90% |
|
|
161
|
+
| React Components | 85% |
|
|
162
|
+
| Critical Paths | 100% |
|
|
163
|
+
|
|
164
|
+
## Test Report Format
|
|
165
|
+
|
|
166
|
+
- **Test Results**: Passed/Failed/Skipped counts
|
|
167
|
+
- **Coverage**: Line, branch, function percentages per layer
|
|
168
|
+
- **Failed Tests**: Detailed error messages and stack traces
|
|
169
|
+
- **Critical Issues**: Blocking issues requiring attention
|
|
170
|
+
- **Recommendations**: Actionable improvements
|
|
171
|
+
|
|
172
|
+
**IMPORTANT:** Use file system to save reports in `./plans/<plan-name>/reports` directory.
|
|
173
|
+
**IMPORTANT:** Sacrifice grammar for concision in reports.
|
|
174
|
+
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
# /cook:contracts - Move Smart Contract Generation
|
|
2
|
+
|
|
3
|
+
Generate Move smart contracts for the Movement blockchain.
|
|
4
|
+
|
|
5
|
+
## Prerequisites
|
|
6
|
+
|
|
7
|
+
### Install Movement CLI
|
|
8
|
+
|
|
9
|
+
Before generating contracts, ensure the Movement CLI is installed. See [Movement CLI docs](https://docs.movementnetwork.xyz/devs/movementcli) for details.
|
|
10
|
+
|
|
11
|
+
#### Quick Install (Testnet - with Move 2 support)
|
|
12
|
+
|
|
13
|
+
**macOS (Apple Silicon/M-series):**
|
|
14
|
+
```bash
|
|
15
|
+
curl -LO https://github.com/movementlabsxyz/homebrew-movement-cli/releases/download/bypass-homebrew/movement-move2-testnet-macos-arm64.tar.gz && mkdir -p temp_extract && tar -xzf movement-move2-testnet-macos-arm64.tar.gz -C temp_extract && chmod +x temp_extract/movement && sudo mv temp_extract/movement /usr/local/bin/movement && rm -rf temp_extract movement-move2-testnet-macos-arm64.tar.gz
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
**macOS (Intel):**
|
|
19
|
+
```bash
|
|
20
|
+
curl -LO https://github.com/movementlabsxyz/homebrew-movement-cli/releases/download/bypass-homebrew/movement-move2-testnet-macos-x86_64.tar.gz && mkdir -p temp_extract && tar -xzf movement-move2-testnet-macos-x86_64.tar.gz -C temp_extract && chmod +x temp_extract/movement && sudo mv temp_extract/movement /usr/local/bin/movement && rm -rf temp_extract movement-move2-testnet-macos-x86_64.tar.gz
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
**Linux (x86_64):**
|
|
24
|
+
```bash
|
|
25
|
+
curl -LO https://github.com/movementlabsxyz/homebrew-movement-cli/releases/download/bypass-homebrew/movement-move2-testnet-linux-x86_64.tar.gz && mkdir -p temp_extract && tar -xzf movement-move2-testnet-linux-x86_64.tar.gz -C temp_extract && chmod +x temp_extract/movement && sudo mv temp_extract/movement /usr/local/bin/movement && rm -rf temp_extract movement-move2-testnet-linux-x86_64.tar.gz
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
**Verify installation:**
|
|
29
|
+
```bash
|
|
30
|
+
movement --version
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### Initialize Account (if not done)
|
|
34
|
+
```bash
|
|
35
|
+
movement init --network testnet
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
This creates a `.movement/config.yaml` with your account credentials.
|
|
39
|
+
|
|
40
|
+
### Get Testnet Tokens
|
|
41
|
+
Visit https://faucet.movementnetwork.xyz/ to get testnet MOVE tokens for deployment.
|
|
42
|
+
|
|
43
|
+
## Workflow
|
|
44
|
+
|
|
45
|
+
### Step 1: Read Move Language Reference
|
|
46
|
+
**CRITICAL:** Always read the Move language reference first:
|
|
47
|
+
```bash
|
|
48
|
+
cat docs/MOVE_LANGUAGE_REFERENCE.md
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Step 2: Analyze Requirements
|
|
52
|
+
From the plan or user request, identify:
|
|
53
|
+
- Module structure
|
|
54
|
+
- Resource definitions
|
|
55
|
+
- Entry functions
|
|
56
|
+
- View functions
|
|
57
|
+
- Events
|
|
58
|
+
- Error codes
|
|
59
|
+
|
|
60
|
+
### Step 3: Generate Move.toml
|
|
61
|
+
```toml
|
|
62
|
+
[package]
|
|
63
|
+
name = "{project_name}"
|
|
64
|
+
version = "1.0.0"
|
|
65
|
+
authors = []
|
|
66
|
+
|
|
67
|
+
[addresses]
|
|
68
|
+
module_addr = "_"
|
|
69
|
+
|
|
70
|
+
[dependencies]
|
|
71
|
+
AptosFramework = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-framework", rev = "mainnet" }
|
|
72
|
+
AptosStdlib = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/aptos-stdlib", rev = "mainnet" }
|
|
73
|
+
MoveStdlib = { git = "https://github.com/aptos-labs/aptos-core.git", subdir = "aptos-move/framework/move-stdlib", rev = "mainnet" }
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Step 4: Generate Move Modules
|
|
77
|
+
Create modules in `contracts/sources/`:
|
|
78
|
+
|
|
79
|
+
```move
|
|
80
|
+
module module_addr::module_name {
|
|
81
|
+
use std::signer;
|
|
82
|
+
use std::string::String;
|
|
83
|
+
use aptos_framework::event;
|
|
84
|
+
use aptos_framework::account;
|
|
85
|
+
|
|
86
|
+
// Error codes
|
|
87
|
+
const E_NOT_AUTHORIZED: u64 = 1;
|
|
88
|
+
const E_ALREADY_EXISTS: u64 = 2;
|
|
89
|
+
|
|
90
|
+
// Resources
|
|
91
|
+
struct ResourceName has key, store {
|
|
92
|
+
field1: u64,
|
|
93
|
+
field2: String,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
// Events
|
|
97
|
+
#[event]
|
|
98
|
+
struct EventName has drop, store {
|
|
99
|
+
field1: u64,
|
|
100
|
+
timestamp: u64,
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// Entry functions
|
|
104
|
+
public entry fun function_name(
|
|
105
|
+
account: &signer,
|
|
106
|
+
param1: u64,
|
|
107
|
+
) acquires ResourceName {
|
|
108
|
+
let addr = signer::address_of(account);
|
|
109
|
+
// Implementation
|
|
110
|
+
event::emit(EventName { field1: param1, timestamp: 0 });
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// View functions
|
|
114
|
+
#[view]
|
|
115
|
+
public fun get_value(addr: address): u64 acquires ResourceName {
|
|
116
|
+
borrow_global<ResourceName>(addr).field1
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Step 5: Generate Unit Tests
|
|
122
|
+
Create tests in `contracts/tests/`:
|
|
123
|
+
|
|
124
|
+
```move
|
|
125
|
+
#[test_only]
|
|
126
|
+
module module_addr::module_name_tests {
|
|
127
|
+
use std::signer;
|
|
128
|
+
use module_addr::module_name;
|
|
129
|
+
|
|
130
|
+
#[test(account = @0x1)]
|
|
131
|
+
fun test_function_name(account: &signer) {
|
|
132
|
+
// Test implementation
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
#[test]
|
|
136
|
+
#[expected_failure(abort_code = module_name::E_NOT_AUTHORIZED)]
|
|
137
|
+
fun test_unauthorized_access() {
|
|
138
|
+
// Test error case
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
### Step 6: Compile and Test
|
|
144
|
+
```bash
|
|
145
|
+
cd contracts
|
|
146
|
+
movement move compile
|
|
147
|
+
movement move test
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Best Practices
|
|
151
|
+
|
|
152
|
+
1. **Resource Safety**: Always use proper resource management
|
|
153
|
+
2. **Access Control**: Validate signers on privileged functions
|
|
154
|
+
3. **Events**: Emit events for all state changes
|
|
155
|
+
4. **Error Codes**: Use descriptive error constants
|
|
156
|
+
5. **Documentation**: Add inline comments for complex logic
|
|
157
|
+
|
|
158
|
+
## Output Summary
|
|
159
|
+
```markdown
|
|
160
|
+
# 📜 Contracts Generated
|
|
161
|
+
|
|
162
|
+
## Modules
|
|
163
|
+
| Module | Functions | Events | Tests |
|
|
164
|
+
|--------|-----------|--------|-------|
|
|
165
|
+
| module_name | 5 | 3 | 10 |
|
|
166
|
+
|
|
167
|
+
## Compilation: ✅ Success
|
|
168
|
+
## Tests: ✅ 10/10 passed
|
|
169
|
+
|
|
170
|
+
## Next Steps
|
|
171
|
+
- Run `/cook:frontend` to generate frontend
|
|
172
|
+
- Run `/test:contracts` for comprehensive testing
|
|
173
|
+
```
|
|
174
|
+
|
|
@@ -0,0 +1,325 @@
|
|
|
1
|
+
# /cook:frontend - React Frontend Generation
|
|
2
|
+
|
|
3
|
+
Generate React frontend with wallet integration for Movement blockchain.
|
|
4
|
+
|
|
5
|
+
## References
|
|
6
|
+
- [TypeScript SDK](https://docs.movementnetwork.xyz/devs/interactonchain/tsSdk)
|
|
7
|
+
- [Wallet Adapter](https://docs.movementnetwork.xyz/devs/interactonchain/wallet-adapter/connect_wallet)
|
|
8
|
+
- [useWallet Hook](https://docs.movementnetwork.xyz/devs/interactonchain/wallet-adapter/useWallet/ConnectWallet)
|
|
9
|
+
- [Sign & Submit](https://docs.movementnetwork.xyz/devs/interactonchain/wallet-adapter/useWallet/signAndSubmitTx)
|
|
10
|
+
|
|
11
|
+
## Movement Network Configuration
|
|
12
|
+
|
|
13
|
+
**Chain IDs:**
|
|
14
|
+
- Mainnet: `126`
|
|
15
|
+
- Testnet: `250`
|
|
16
|
+
|
|
17
|
+
**RPC Endpoints:**
|
|
18
|
+
- Mainnet: `https://mainnet.movementnetwork.xyz/v1`
|
|
19
|
+
- Testnet: `https://full.testnet.movementinfra.xyz/v1`
|
|
20
|
+
|
|
21
|
+
**Explorer:**
|
|
22
|
+
- `https://explorer.movementnetwork.xyz/txn/{txHash}?network={mainnet|testnet}`
|
|
23
|
+
|
|
24
|
+
## Workflow
|
|
25
|
+
|
|
26
|
+
### Step 1: Analyze Requirements
|
|
27
|
+
From the plan or contracts, identify:
|
|
28
|
+
- UI components needed
|
|
29
|
+
- User interactions
|
|
30
|
+
- Contract functions to call (entry functions vs view functions)
|
|
31
|
+
- Data display needs
|
|
32
|
+
|
|
33
|
+
### Step 2: Generate package.json
|
|
34
|
+
```json
|
|
35
|
+
{
|
|
36
|
+
"name": "{project_name}-frontend",
|
|
37
|
+
"version": "1.0.0",
|
|
38
|
+
"type": "module",
|
|
39
|
+
"scripts": {
|
|
40
|
+
"dev": "vite",
|
|
41
|
+
"build": "tsc && vite build",
|
|
42
|
+
"preview": "vite preview",
|
|
43
|
+
"test": "vitest"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"@aptos-labs/ts-sdk": "^1.33.1",
|
|
47
|
+
"@aptos-labs/wallet-adapter-react": "^3.7.0",
|
|
48
|
+
"react": "^18.2.0",
|
|
49
|
+
"react-dom": "^18.2.0"
|
|
50
|
+
},
|
|
51
|
+
"devDependencies": {
|
|
52
|
+
"@types/react": "^18.2.0",
|
|
53
|
+
"@types/react-dom": "^18.2.0",
|
|
54
|
+
"@vitejs/plugin-react": "^4.2.0",
|
|
55
|
+
"typescript": "^5.3.0",
|
|
56
|
+
"vite": "^5.0.0",
|
|
57
|
+
"vitest": "^1.0.0"
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Step 3: Generate Environment Configuration
|
|
63
|
+
`frontend/.env`:
|
|
64
|
+
```bash
|
|
65
|
+
VITE_MODULE_ADDRESS=<YOUR_CONTRACT_ADDRESS>
|
|
66
|
+
VITE_NETWORK=testnet
|
|
67
|
+
VITE_NODE_URL=https://full.testnet.movementinfra.xyz/v1
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Step 4: Generate Wallet Provider
|
|
71
|
+
`frontend/src/contexts/WalletProvider.tsx`:
|
|
72
|
+
```tsx
|
|
73
|
+
import { AptosWalletAdapterProvider } from "@aptos-labs/wallet-adapter-react";
|
|
74
|
+
import { AptosConfig, Network } from "@aptos-labs/ts-sdk";
|
|
75
|
+
import { PropsWithChildren } from "react";
|
|
76
|
+
|
|
77
|
+
export function WalletProvider({ children }: PropsWithChildren) {
|
|
78
|
+
// Movement Network configuration
|
|
79
|
+
const config = new AptosConfig({
|
|
80
|
+
network: Network.CUSTOM,
|
|
81
|
+
fullnode: import.meta.env.VITE_NODE_URL || 'https://full.testnet.movementinfra.xyz/v1',
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
return (
|
|
85
|
+
<AptosWalletAdapterProvider
|
|
86
|
+
plugins={[]}
|
|
87
|
+
autoConnect={true}
|
|
88
|
+
dappConfig={config}
|
|
89
|
+
onError={(error) => {
|
|
90
|
+
console.error("Wallet error:", error);
|
|
91
|
+
}}
|
|
92
|
+
>
|
|
93
|
+
{children}
|
|
94
|
+
</AptosWalletAdapterProvider>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### Step 5: Generate Custom Hooks
|
|
100
|
+
`frontend/src/hooks/useContract.ts`:
|
|
101
|
+
```tsx
|
|
102
|
+
import { useWallet } from "@aptos-labs/wallet-adapter-react";
|
|
103
|
+
import { Aptos, AptosConfig, Network } from "@aptos-labs/ts-sdk";
|
|
104
|
+
|
|
105
|
+
const MODULE_ADDRESS = import.meta.env.VITE_MODULE_ADDRESS;
|
|
106
|
+
const MODULE_NAME = "{module_name}";
|
|
107
|
+
|
|
108
|
+
// Create Aptos client for Movement Network
|
|
109
|
+
const aptosConfig = new AptosConfig({
|
|
110
|
+
network: Network.CUSTOM,
|
|
111
|
+
fullnode: import.meta.env.VITE_NODE_URL || "https://full.testnet.movementinfra.xyz/v1",
|
|
112
|
+
});
|
|
113
|
+
const aptos = new Aptos(aptosConfig);
|
|
114
|
+
|
|
115
|
+
export function useContract() {
|
|
116
|
+
const { signAndSubmitTransaction, account, connected } = useWallet();
|
|
117
|
+
|
|
118
|
+
// Call entry function (modifies state, requires signing)
|
|
119
|
+
const callFunction = async (functionName: string, args: any[]) => {
|
|
120
|
+
if (!connected || !account) throw new Error("Wallet not connected");
|
|
121
|
+
|
|
122
|
+
const response = await signAndSubmitTransaction({
|
|
123
|
+
data: {
|
|
124
|
+
function: `${MODULE_ADDRESS}::${MODULE_NAME}::${functionName}`,
|
|
125
|
+
functionArguments: args,
|
|
126
|
+
},
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
// Wait for transaction confirmation
|
|
130
|
+
const result = await aptos.waitForTransaction({
|
|
131
|
+
transactionHash: response.hash
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
return result;
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
// Call view function (read-only, no signing required)
|
|
138
|
+
const viewFunction = async (functionName: string, args: any[]) => {
|
|
139
|
+
return await aptos.view({
|
|
140
|
+
payload: {
|
|
141
|
+
function: `${MODULE_ADDRESS}::${MODULE_NAME}::${functionName}`,
|
|
142
|
+
functionArguments: args,
|
|
143
|
+
},
|
|
144
|
+
});
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
return { callFunction, viewFunction, account, connected, aptos };
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Step 6: Generate Wallet Connect Component
|
|
152
|
+
`frontend/src/components/WalletConnect.tsx`:
|
|
153
|
+
```tsx
|
|
154
|
+
import { useWallet } from "@aptos-labs/wallet-adapter-react";
|
|
155
|
+
|
|
156
|
+
export function WalletConnect() {
|
|
157
|
+
const {
|
|
158
|
+
connect,
|
|
159
|
+
disconnect,
|
|
160
|
+
account,
|
|
161
|
+
connected,
|
|
162
|
+
wallets,
|
|
163
|
+
isLoading
|
|
164
|
+
} = useWallet();
|
|
165
|
+
|
|
166
|
+
if (isLoading) {
|
|
167
|
+
return <button disabled>Loading...</button>;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
if (connected && account) {
|
|
171
|
+
return (
|
|
172
|
+
<div className="wallet-connected">
|
|
173
|
+
<span className="address">
|
|
174
|
+
{account.address.slice(0, 6)}...{account.address.slice(-4)}
|
|
175
|
+
</span>
|
|
176
|
+
<button onClick={disconnect}>Disconnect</button>
|
|
177
|
+
</div>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
return (
|
|
182
|
+
<div className="wallet-select">
|
|
183
|
+
{wallets?.filter(w => w.readyState === 'Installed').map((wallet) => (
|
|
184
|
+
<button
|
|
185
|
+
key={wallet.name}
|
|
186
|
+
onClick={() => connect(wallet.name)}
|
|
187
|
+
>
|
|
188
|
+
Connect {wallet.name}
|
|
189
|
+
</button>
|
|
190
|
+
))}
|
|
191
|
+
{wallets?.filter(w => w.readyState === 'Installed').length === 0 && (
|
|
192
|
+
<p>No wallets detected. Please install a Movement-compatible wallet.</p>
|
|
193
|
+
)}
|
|
194
|
+
</div>
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Step 7: Generate Main App
|
|
200
|
+
`frontend/src/App.tsx`:
|
|
201
|
+
```tsx
|
|
202
|
+
import { WalletProvider } from "./contexts/WalletProvider";
|
|
203
|
+
import { WalletConnect } from "./components/WalletConnect";
|
|
204
|
+
|
|
205
|
+
export default function App() {
|
|
206
|
+
return (
|
|
207
|
+
<WalletProvider>
|
|
208
|
+
<div className="app">
|
|
209
|
+
<header>
|
|
210
|
+
<h1>{Project Name}</h1>
|
|
211
|
+
<WalletConnect />
|
|
212
|
+
</header>
|
|
213
|
+
<main>
|
|
214
|
+
{/* Main content - add your components here */}
|
|
215
|
+
</main>
|
|
216
|
+
</div>
|
|
217
|
+
</WalletProvider>
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### Step 8: Generate Vite Config
|
|
223
|
+
`frontend/vite.config.ts`:
|
|
224
|
+
```ts
|
|
225
|
+
import { defineConfig } from 'vite';
|
|
226
|
+
import react from '@vitejs/plugin-react';
|
|
227
|
+
|
|
228
|
+
export default defineConfig({
|
|
229
|
+
plugins: [react()],
|
|
230
|
+
define: {
|
|
231
|
+
'process.env': {},
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
### Step 9: Generate TypeScript Config
|
|
237
|
+
`frontend/tsconfig.json`:
|
|
238
|
+
```json
|
|
239
|
+
{
|
|
240
|
+
"compilerOptions": {
|
|
241
|
+
"target": "ES2020",
|
|
242
|
+
"useDefineForClassFields": true,
|
|
243
|
+
"lib": ["ES2020", "DOM", "DOM.Iterable"],
|
|
244
|
+
"module": "ESNext",
|
|
245
|
+
"skipLibCheck": true,
|
|
246
|
+
"moduleResolution": "bundler",
|
|
247
|
+
"allowImportingTsExtensions": true,
|
|
248
|
+
"resolveJsonModule": true,
|
|
249
|
+
"isolatedModules": true,
|
|
250
|
+
"noEmit": true,
|
|
251
|
+
"jsx": "react-jsx",
|
|
252
|
+
"strict": true,
|
|
253
|
+
"noUnusedLocals": true,
|
|
254
|
+
"noUnusedParameters": true,
|
|
255
|
+
"noFallthroughCasesInSwitch": true
|
|
256
|
+
},
|
|
257
|
+
"include": ["src"]
|
|
258
|
+
}
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Common Patterns
|
|
262
|
+
|
|
263
|
+
### Reading Contract State
|
|
264
|
+
```tsx
|
|
265
|
+
const { viewFunction } = useContract();
|
|
266
|
+
|
|
267
|
+
// Read a value from contract
|
|
268
|
+
const fetchData = async () => {
|
|
269
|
+
const [result] = await viewFunction("get_value", []);
|
|
270
|
+
setValue(Number(result));
|
|
271
|
+
};
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Writing to Contract
|
|
275
|
+
```tsx
|
|
276
|
+
const { callFunction, connected } = useContract();
|
|
277
|
+
|
|
278
|
+
const handleSubmit = async () => {
|
|
279
|
+
if (!connected) return;
|
|
280
|
+
|
|
281
|
+
try {
|
|
282
|
+
const result = await callFunction("set_value", [newValue]);
|
|
283
|
+
console.log("Transaction successful:", result.hash);
|
|
284
|
+
} catch (error) {
|
|
285
|
+
console.error("Transaction failed:", error);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### Transaction Status
|
|
291
|
+
```tsx
|
|
292
|
+
const [txStatus, setTxStatus] = useState<'idle' | 'pending' | 'success' | 'error'>('idle');
|
|
293
|
+
|
|
294
|
+
const handleTransaction = async () => {
|
|
295
|
+
setTxStatus('pending');
|
|
296
|
+
try {
|
|
297
|
+
await callFunction("some_function", []);
|
|
298
|
+
setTxStatus('success');
|
|
299
|
+
} catch {
|
|
300
|
+
setTxStatus('error');
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Output Summary
|
|
306
|
+
```markdown
|
|
307
|
+
# 🎨 Frontend Generated
|
|
308
|
+
|
|
309
|
+
## Files Created
|
|
310
|
+
- src/App.tsx
|
|
311
|
+
- src/contexts/WalletProvider.tsx
|
|
312
|
+
- src/hooks/useContract.ts
|
|
313
|
+
- src/components/WalletConnect.tsx
|
|
314
|
+
- src/components/{additional components}
|
|
315
|
+
- vite.config.ts
|
|
316
|
+
- tsconfig.json
|
|
317
|
+
- .env
|
|
318
|
+
|
|
319
|
+
## Next Steps
|
|
320
|
+
1. Run `npm install` to install dependencies
|
|
321
|
+
2. Update `.env` with your contract address
|
|
322
|
+
3. Run `npm run dev` to start development server
|
|
323
|
+
4. Install a Movement-compatible wallet (Razor, Nightly, etc.)
|
|
324
|
+
5. Connect wallet and test interactions
|
|
325
|
+
```
|