@5ive-tech/cli 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/README.md +226 -0
- package/dist/assets/vm/five_vm_wasm.d.ts +762 -0
- package/dist/assets/vm/five_vm_wasm.js +3754 -0
- package/dist/assets/vm/five_vm_wasm_bg.wasm +0 -0
- package/dist/assets/vm/five_vm_wasm_bg.wasm.d.ts +247 -0
- package/dist/assets/vm/package.json +11 -0
- package/dist/cli.d.ts +47 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +343 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/analyze.d.ts +3 -0
- package/dist/commands/analyze.d.ts.map +1 -0
- package/dist/commands/analyze.js +435 -0
- package/dist/commands/analyze.js.map +1 -0
- package/dist/commands/build.d.ts +3 -0
- package/dist/commands/build.d.ts.map +1 -0
- package/dist/commands/build.js +66 -0
- package/dist/commands/build.js.map +1 -0
- package/dist/commands/compile.d.ts +3 -0
- package/dist/commands/compile.d.ts.map +1 -0
- package/dist/commands/compile.js +872 -0
- package/dist/commands/compile.js.map +1 -0
- package/dist/commands/config.d.ts +3 -0
- package/dist/commands/config.d.ts.map +1 -0
- package/dist/commands/config.js +431 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/deploy-and-execute.d.ts +3 -0
- package/dist/commands/deploy-and-execute.d.ts.map +1 -0
- package/dist/commands/deploy-and-execute.js +317 -0
- package/dist/commands/deploy-and-execute.js.map +1 -0
- package/dist/commands/deploy.d.ts +21 -0
- package/dist/commands/deploy.d.ts.map +1 -0
- package/dist/commands/deploy.js +806 -0
- package/dist/commands/deploy.js.map +1 -0
- package/dist/commands/donate.d.ts +4 -0
- package/dist/commands/donate.d.ts.map +1 -0
- package/dist/commands/donate.js +104 -0
- package/dist/commands/donate.js.map +1 -0
- package/dist/commands/execute.d.ts +6 -0
- package/dist/commands/execute.d.ts.map +1 -0
- package/dist/commands/execute.js +749 -0
- package/dist/commands/execute.js.map +1 -0
- package/dist/commands/fmt.d.ts +3 -0
- package/dist/commands/fmt.d.ts.map +1 -0
- package/dist/commands/fmt.js +327 -0
- package/dist/commands/fmt.js.map +1 -0
- package/dist/commands/help.d.ts +6 -0
- package/dist/commands/help.d.ts.map +1 -0
- package/dist/commands/help.js +224 -0
- package/dist/commands/help.js.map +1 -0
- package/dist/commands/index.d.ts +45 -0
- package/dist/commands/index.d.ts.map +1 -0
- package/dist/commands/index.js +119 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +3 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +887 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/local.d.ts +3 -0
- package/dist/commands/local.d.ts.map +1 -0
- package/dist/commands/local.js +703 -0
- package/dist/commands/local.js.map +1 -0
- package/dist/commands/namespace.d.ts +3 -0
- package/dist/commands/namespace.d.ts.map +1 -0
- package/dist/commands/namespace.js +328 -0
- package/dist/commands/namespace.js.map +1 -0
- package/dist/commands/template.d.ts +4 -0
- package/dist/commands/template.d.ts.map +1 -0
- package/dist/commands/template.js +486 -0
- package/dist/commands/template.js.map +1 -0
- package/dist/commands/test.d.ts +6 -0
- package/dist/commands/test.d.ts.map +1 -0
- package/dist/commands/test.js +890 -0
- package/dist/commands/test.js.map +1 -0
- package/dist/commands/version.d.ts +6 -0
- package/dist/commands/version.d.ts.map +1 -0
- package/dist/commands/version.js +339 -0
- package/dist/commands/version.js.map +1 -0
- package/dist/config/ConfigManager.d.ts +69 -0
- package/dist/config/ConfigManager.d.ts.map +1 -0
- package/dist/config/ConfigManager.js +261 -0
- package/dist/config/ConfigManager.js.map +1 -0
- package/dist/config/index.d.ts +10 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +21 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +35 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +105 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/project/ProjectLoader.d.ts +12 -0
- package/dist/project/ProjectLoader.d.ts.map +1 -0
- package/dist/project/ProjectLoader.js +115 -0
- package/dist/project/ProjectLoader.js.map +1 -0
- package/dist/types.d.ts +334 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/AccountFixtureGenerator.d.ts +48 -0
- package/dist/utils/AccountFixtureGenerator.d.ts.map +1 -0
- package/dist/utils/AccountFixtureGenerator.js +265 -0
- package/dist/utils/AccountFixtureGenerator.js.map +1 -0
- package/dist/utils/FiveFileManager.d.ts +96 -0
- package/dist/utils/FiveFileManager.d.ts.map +1 -0
- package/dist/utils/FiveFileManager.js +329 -0
- package/dist/utils/FiveFileManager.js.map +1 -0
- package/dist/utils/ascii-art.d.ts +72 -0
- package/dist/utils/ascii-art.d.ts.map +1 -0
- package/dist/utils/ascii-art.js +314 -0
- package/dist/utils/ascii-art.js.map +1 -0
- package/dist/utils/cli-ui.d.ts +39 -0
- package/dist/utils/cli-ui.d.ts.map +1 -0
- package/dist/utils/cli-ui.js +75 -0
- package/dist/utils/cli-ui.js.map +1 -0
- package/dist/utils/fileUtils.d.ts +25 -0
- package/dist/utils/fileUtils.d.ts.map +1 -0
- package/dist/utils/fileUtils.js +50 -0
- package/dist/utils/fileUtils.js.map +1 -0
- package/dist/utils/logger.d.ts +53 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +287 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/wasm/compiler.d.ts +101 -0
- package/dist/wasm/compiler.d.ts.map +1 -0
- package/dist/wasm/compiler.js +906 -0
- package/dist/wasm/compiler.js.map +1 -0
- package/dist/wasm/loader.d.ts +2 -0
- package/dist/wasm/loader.d.ts.map +1 -0
- package/dist/wasm/loader.js +90 -0
- package/dist/wasm/loader.js.map +1 -0
- package/dist/wasm/vm.d.ts +32 -0
- package/dist/wasm/vm.d.ts.map +1 -0
- package/dist/wasm/vm.js +440 -0
- package/dist/wasm/vm.js.map +1 -0
- package/package.json +100 -0
|
@@ -0,0 +1,887 @@
|
|
|
1
|
+
// Init command.
|
|
2
|
+
import { writeFile, mkdir, access } from 'fs/promises';
|
|
3
|
+
import { join } from 'path';
|
|
4
|
+
import chalk from 'chalk';
|
|
5
|
+
import ora from 'ora';
|
|
6
|
+
import { success as uiSuccess, warning as uiWarning, uiColors } from '../utils/cli-ui.js';
|
|
7
|
+
export const initCommand = {
|
|
8
|
+
name: 'init',
|
|
9
|
+
description: 'Initialize new project',
|
|
10
|
+
aliases: ['new', 'create'],
|
|
11
|
+
options: [
|
|
12
|
+
{
|
|
13
|
+
flags: '-t, --template <template>',
|
|
14
|
+
description: 'Project template',
|
|
15
|
+
choices: ['basic', 'defi', 'nft', 'game', 'dao'],
|
|
16
|
+
defaultValue: 'basic'
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
flags: '--target <target>',
|
|
20
|
+
description: 'Default compilation target',
|
|
21
|
+
choices: ['vm', 'solana', 'debug', 'test'],
|
|
22
|
+
defaultValue: 'vm'
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
flags: '--name <name>',
|
|
26
|
+
description: 'Project name (default: directory name)',
|
|
27
|
+
required: false
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
flags: '--description <desc>',
|
|
31
|
+
description: 'Project description',
|
|
32
|
+
required: false
|
|
33
|
+
},
|
|
34
|
+
{
|
|
35
|
+
flags: '--author <author>',
|
|
36
|
+
description: 'Project author',
|
|
37
|
+
required: false
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
flags: '--license <license>',
|
|
41
|
+
description: 'Project license',
|
|
42
|
+
defaultValue: 'MIT'
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
flags: '--no-git',
|
|
46
|
+
description: 'Skip git repository initialization',
|
|
47
|
+
defaultValue: false
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
flags: '--no-examples',
|
|
51
|
+
description: 'Skip example files',
|
|
52
|
+
defaultValue: false
|
|
53
|
+
}
|
|
54
|
+
],
|
|
55
|
+
arguments: [
|
|
56
|
+
{
|
|
57
|
+
name: 'directory',
|
|
58
|
+
description: 'Project directory (default: current directory)',
|
|
59
|
+
required: false
|
|
60
|
+
}
|
|
61
|
+
],
|
|
62
|
+
examples: [
|
|
63
|
+
{
|
|
64
|
+
command: 'five init',
|
|
65
|
+
description: 'Initialize project in current directory'
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
command: 'five init my-project',
|
|
69
|
+
description: 'Create new project in my-project directory'
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
command: 'five init my-defi --template defi --target solana',
|
|
73
|
+
description: 'Create DeFi project targeting Solana'
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
command: 'five init game --template game --no-git',
|
|
77
|
+
description: 'Create game project without git initialization'
|
|
78
|
+
}
|
|
79
|
+
],
|
|
80
|
+
handler: async (args, options, context) => {
|
|
81
|
+
const { logger } = context;
|
|
82
|
+
try {
|
|
83
|
+
// Determine project directory
|
|
84
|
+
const projectDir = args[0] || process.cwd();
|
|
85
|
+
const projectName = options.name || (args[0] ? args[0] : 'five-project');
|
|
86
|
+
logger.info(`Initializing Five VM project: ${projectName}`);
|
|
87
|
+
// Check if directory exists and is empty
|
|
88
|
+
await checkProjectDirectory(projectDir, logger);
|
|
89
|
+
// Create project structure
|
|
90
|
+
const spinner = ora('Creating project structure...').start();
|
|
91
|
+
await createProjectStructure(projectDir, options.template);
|
|
92
|
+
spinner.succeed('Project structure created');
|
|
93
|
+
// Generate project configuration
|
|
94
|
+
spinner.start('Generating configuration files...');
|
|
95
|
+
await generateProjectConfig(projectDir, projectName, options);
|
|
96
|
+
await generatePackageJson(projectDir, projectName, options);
|
|
97
|
+
spinner.succeed('Configuration files generated');
|
|
98
|
+
// Generate source files
|
|
99
|
+
if (!options.noExamples) {
|
|
100
|
+
spinner.start('Generating example files...');
|
|
101
|
+
await generateExampleFiles(projectDir, options.template);
|
|
102
|
+
spinner.succeed('Example files generated');
|
|
103
|
+
}
|
|
104
|
+
// Initialize git repository
|
|
105
|
+
if (!options.noGit) {
|
|
106
|
+
spinner.start('Initializing git repository...');
|
|
107
|
+
await initializeGitRepository(projectDir);
|
|
108
|
+
spinner.succeed('Git repository initialized');
|
|
109
|
+
}
|
|
110
|
+
// Display success message
|
|
111
|
+
displaySuccessMessage(projectDir, projectName, options);
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
logger.error('Project initialization failed:', error);
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
async function checkProjectDirectory(projectDir, logger) {
|
|
120
|
+
try {
|
|
121
|
+
await access(projectDir);
|
|
122
|
+
// Directory exists, check if it's empty
|
|
123
|
+
const { readdir } = await import('fs/promises');
|
|
124
|
+
const files = await readdir(projectDir);
|
|
125
|
+
if (files.length > 0) {
|
|
126
|
+
logger.warn(`Directory ${projectDir} is not empty`);
|
|
127
|
+
// Check for existing Five project
|
|
128
|
+
const hasConfig = files.includes('five.toml') || files.includes('package.json');
|
|
129
|
+
if (hasConfig) {
|
|
130
|
+
throw new Error('Directory already contains a project configuration');
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
catch (error) {
|
|
135
|
+
if (error.code === 'ENOENT') {
|
|
136
|
+
// Directory doesn't exist, create it
|
|
137
|
+
await mkdir(projectDir, { recursive: true });
|
|
138
|
+
}
|
|
139
|
+
else {
|
|
140
|
+
throw error;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
async function createProjectStructure(projectDir, template) {
|
|
145
|
+
const dirs = [
|
|
146
|
+
'src',
|
|
147
|
+
'tests',
|
|
148
|
+
'examples',
|
|
149
|
+
'build',
|
|
150
|
+
'docs',
|
|
151
|
+
'.five'
|
|
152
|
+
];
|
|
153
|
+
// Add template-specific directories
|
|
154
|
+
switch (template) {
|
|
155
|
+
case 'defi':
|
|
156
|
+
dirs.push('src/protocols', 'src/tokens', 'src/pools');
|
|
157
|
+
break;
|
|
158
|
+
case 'nft':
|
|
159
|
+
dirs.push('src/collections', 'src/metadata', 'assets');
|
|
160
|
+
break;
|
|
161
|
+
case 'game':
|
|
162
|
+
dirs.push('src/entities', 'src/systems', 'src/components', 'assets');
|
|
163
|
+
break;
|
|
164
|
+
case 'dao':
|
|
165
|
+
dirs.push('src/governance', 'src/treasury', 'src/proposals');
|
|
166
|
+
break;
|
|
167
|
+
}
|
|
168
|
+
for (const dir of dirs) {
|
|
169
|
+
await mkdir(join(projectDir, dir), { recursive: true });
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async function generateProjectConfig(projectDir, projectName, options) {
|
|
173
|
+
const config = {
|
|
174
|
+
name: projectName,
|
|
175
|
+
version: '0.1.0',
|
|
176
|
+
description: options.description || `A Five VM project`,
|
|
177
|
+
sourceDir: 'src',
|
|
178
|
+
buildDir: 'build',
|
|
179
|
+
target: options.target,
|
|
180
|
+
optimizations: {
|
|
181
|
+
enableCompression: true,
|
|
182
|
+
enableConstraintOptimization: true,
|
|
183
|
+
optimizationLevel: 'production'
|
|
184
|
+
},
|
|
185
|
+
dependencies: []
|
|
186
|
+
};
|
|
187
|
+
const configContent = generateTomlConfig(config);
|
|
188
|
+
await writeFile(join(projectDir, 'five.toml'), configContent);
|
|
189
|
+
}
|
|
190
|
+
async function generatePackageJson(projectDir, projectName, options) {
|
|
191
|
+
const packageJson = {
|
|
192
|
+
name: projectName.toLowerCase().replace(/[^a-z0-9-]/g, '-'),
|
|
193
|
+
version: '0.1.0',
|
|
194
|
+
description: options.description || 'A Five VM project',
|
|
195
|
+
author: options.author || '',
|
|
196
|
+
license: options.license,
|
|
197
|
+
scripts: {
|
|
198
|
+
build: 'five compile src/**/*.v',
|
|
199
|
+
test: 'five test',
|
|
200
|
+
deploy: 'five deploy',
|
|
201
|
+
'build:release': 'five compile src/**/*.v -O 3',
|
|
202
|
+
'build:debug': 'five compile src/**/*.v --debug',
|
|
203
|
+
'watch': 'five compile src/**/*.v --watch'
|
|
204
|
+
},
|
|
205
|
+
devDependencies: {
|
|
206
|
+
'five-cli': '^1.0.0'
|
|
207
|
+
},
|
|
208
|
+
keywords: [
|
|
209
|
+
'five-vm',
|
|
210
|
+
'blockchain',
|
|
211
|
+
'solana',
|
|
212
|
+
'smart-contracts'
|
|
213
|
+
]
|
|
214
|
+
};
|
|
215
|
+
await writeFile(join(projectDir, 'package.json'), JSON.stringify(packageJson, null, 2));
|
|
216
|
+
}
|
|
217
|
+
async function generateExampleFiles(projectDir, template) {
|
|
218
|
+
// Generate main source file
|
|
219
|
+
const mainFile = getTemplateMainFile(template);
|
|
220
|
+
await writeFile(join(projectDir, 'src/main.v'), mainFile);
|
|
221
|
+
// Generate test file
|
|
222
|
+
const testFile = getTemplateTestFile(template);
|
|
223
|
+
await writeFile(join(projectDir, 'tests/main.test.v'), testFile);
|
|
224
|
+
// Generate README
|
|
225
|
+
const readme = generateReadme(template);
|
|
226
|
+
await writeFile(join(projectDir, 'README.md'), readme);
|
|
227
|
+
// Generate .gitignore
|
|
228
|
+
const gitignore = generateGitignore();
|
|
229
|
+
await writeFile(join(projectDir, '.gitignore'), gitignore);
|
|
230
|
+
}
|
|
231
|
+
async function initializeGitRepository(projectDir) {
|
|
232
|
+
const { execSync } = await import('child_process');
|
|
233
|
+
try {
|
|
234
|
+
execSync('git init', { cwd: projectDir, stdio: 'ignore' });
|
|
235
|
+
execSync('git add .', { cwd: projectDir, stdio: 'ignore' });
|
|
236
|
+
execSync('git commit -m "Initial commit"', { cwd: projectDir, stdio: 'ignore' });
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
// Git initialization is optional, don't fail the entire process
|
|
240
|
+
console.warn(uiWarning('Git initialization failed'));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
function generateTomlConfig(config) {
|
|
244
|
+
return `# Five VM Project Configuration
|
|
245
|
+
[project]
|
|
246
|
+
name = "${config.name}"
|
|
247
|
+
version = "${config.version}"
|
|
248
|
+
description = "${config.description}"
|
|
249
|
+
source_dir = "${config.sourceDir}"
|
|
250
|
+
build_dir = "${config.buildDir}"
|
|
251
|
+
target = "${config.target}"
|
|
252
|
+
|
|
253
|
+
[optimizations]
|
|
254
|
+
enable_compression = ${config.optimizations.enableCompression}
|
|
255
|
+
enable_constraint_optimization = ${config.optimizations.enableConstraintOptimization}
|
|
256
|
+
optimization_level = "${config.optimizations.optimizationLevel}"
|
|
257
|
+
|
|
258
|
+
[dependencies]
|
|
259
|
+
# Add project dependencies here
|
|
260
|
+
# example = { path = "../example" }
|
|
261
|
+
|
|
262
|
+
[build]
|
|
263
|
+
# Custom build settings
|
|
264
|
+
max_bytecode_size = 1048576 # 1MB
|
|
265
|
+
target_compute_units = 200000
|
|
266
|
+
|
|
267
|
+
[deploy]
|
|
268
|
+
# Deployment settings
|
|
269
|
+
network = "devnet"
|
|
270
|
+
# program_id = "your-program-id"
|
|
271
|
+
`;
|
|
272
|
+
}
|
|
273
|
+
function getTemplateMainFile(template) {
|
|
274
|
+
const templates = {
|
|
275
|
+
basic: `// Basic Five VM Program
|
|
276
|
+
script BasicProgram {
|
|
277
|
+
// Program initialization
|
|
278
|
+
init() {
|
|
279
|
+
log("BasicProgram initialized");
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// Main program constraints
|
|
283
|
+
constraints {
|
|
284
|
+
// Add your business logic here
|
|
285
|
+
require(true, "Always passes");
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
// Main entry point
|
|
290
|
+
instruction main() {
|
|
291
|
+
log("Hello, Five VM!");
|
|
292
|
+
42 // Return value
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// Example function with parameters
|
|
296
|
+
instruction add(a: u64, b: u64) -> u64 {
|
|
297
|
+
a + b
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
#[test]
|
|
301
|
+
instruction test_add() {
|
|
302
|
+
let result = add(2, 3);
|
|
303
|
+
assert_eq(result, 5, "Addition should work");
|
|
304
|
+
}
|
|
305
|
+
`,
|
|
306
|
+
defi: `// DeFi Protocol on Five VM
|
|
307
|
+
script DefiProtocol {
|
|
308
|
+
init() {
|
|
309
|
+
log("DeFi Protocol initialized");
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
constraints {
|
|
313
|
+
// Ensure minimum liquidity
|
|
314
|
+
require(get_balance() >= 1000, "Insufficient liquidity");
|
|
315
|
+
|
|
316
|
+
// Validate price oracle
|
|
317
|
+
let price = get_price_oracle();
|
|
318
|
+
require(price > 0, "Invalid price");
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
account LiquidityPool {
|
|
323
|
+
token_a_amount: u64,
|
|
324
|
+
token_b_amount: u64,
|
|
325
|
+
total_shares: u64,
|
|
326
|
+
fee_rate: u64
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
instruction swap(amount_in: u64, token_in: string) -> u64 {
|
|
330
|
+
let pool = load_account<LiquidityPool>(0);
|
|
331
|
+
|
|
332
|
+
if token_in == "A" {
|
|
333
|
+
let amount_out = (amount_in * pool.token_b_amount) / (pool.token_a_amount + amount_in);
|
|
334
|
+
pool.token_a_amount += amount_in;
|
|
335
|
+
pool.token_b_amount -= amount_out;
|
|
336
|
+
amount_out
|
|
337
|
+
} else {
|
|
338
|
+
let amount_out = (amount_in * pool.token_a_amount) / (pool.token_b_amount + amount_in);
|
|
339
|
+
pool.token_b_amount += amount_in;
|
|
340
|
+
pool.token_a_amount -= amount_out;
|
|
341
|
+
amount_out
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
instruction add_liquidity(amount_a: u64, amount_b: u64) -> u64 {
|
|
346
|
+
let pool = load_account<LiquidityPool>(0);
|
|
347
|
+
|
|
348
|
+
let shares = if pool.total_shares == 0 {
|
|
349
|
+
(amount_a * amount_b).sqrt()
|
|
350
|
+
} else {
|
|
351
|
+
min(
|
|
352
|
+
(amount_a * pool.total_shares) / pool.token_a_amount,
|
|
353
|
+
(amount_b * pool.total_shares) / pool.token_b_amount
|
|
354
|
+
)
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
pool.token_a_amount += amount_a;
|
|
358
|
+
pool.token_b_amount += amount_b;
|
|
359
|
+
pool.total_shares += shares;
|
|
360
|
+
|
|
361
|
+
shares
|
|
362
|
+
}
|
|
363
|
+
`,
|
|
364
|
+
nft: `// NFT Collection on Five VM
|
|
365
|
+
script NFTCollection {
|
|
366
|
+
init() {
|
|
367
|
+
log("NFT Collection initialized");
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
constraints {
|
|
371
|
+
// Ensure valid mint authority
|
|
372
|
+
require(is_mint_authority(), "Invalid mint authority");
|
|
373
|
+
|
|
374
|
+
// Check collection size limits
|
|
375
|
+
let current_supply = get_current_supply();
|
|
376
|
+
require(current_supply < 10000, "Max supply reached");
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
account NFTMetadata {
|
|
381
|
+
name: string,
|
|
382
|
+
symbol: string,
|
|
383
|
+
uri: string,
|
|
384
|
+
creator: pubkey,
|
|
385
|
+
collection: pubkey,
|
|
386
|
+
is_mutable: bool
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
instruction mint_nft(to: pubkey, metadata_uri: string) -> pubkey {
|
|
390
|
+
let nft_id = derive_pda("nft", [to, get_clock().slot]);
|
|
391
|
+
|
|
392
|
+
let metadata = NFTMetadata {
|
|
393
|
+
name: "Five VM NFT",
|
|
394
|
+
symbol: "FVM",
|
|
395
|
+
uri: metadata_uri,
|
|
396
|
+
creator: get_signer(),
|
|
397
|
+
collection: get_program_id(),
|
|
398
|
+
is_mutable: true
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
create_account(nft_id, metadata);
|
|
402
|
+
log("NFT minted successfully");
|
|
403
|
+
|
|
404
|
+
nft_id
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
instruction transfer_nft(nft_id: pubkey, from: pubkey, to: pubkey) {
|
|
408
|
+
require(is_signer(from), "Invalid signature");
|
|
409
|
+
|
|
410
|
+
let metadata = load_account<NFTMetadata>(nft_id);
|
|
411
|
+
require(metadata.creator == from, "Not owner");
|
|
412
|
+
|
|
413
|
+
// Update ownership (simplified)
|
|
414
|
+
metadata.creator = to;
|
|
415
|
+
save_account(nft_id, metadata);
|
|
416
|
+
|
|
417
|
+
emit TransferEvent { from, to, nft_id };
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
event TransferEvent {
|
|
421
|
+
from: pubkey,
|
|
422
|
+
to: pubkey,
|
|
423
|
+
nft_id: pubkey
|
|
424
|
+
}
|
|
425
|
+
`,
|
|
426
|
+
game: `// Game Logic on Five VM
|
|
427
|
+
script GameEngine {
|
|
428
|
+
init() {
|
|
429
|
+
log("Game Engine initialized");
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
constraints {
|
|
433
|
+
// Validate player actions
|
|
434
|
+
let player = get_player();
|
|
435
|
+
require(player.is_active, "Player not active");
|
|
436
|
+
|
|
437
|
+
// Check game state
|
|
438
|
+
let game_state = get_game_state();
|
|
439
|
+
require(game_state == "active", "Game not active");
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
account Player {
|
|
444
|
+
id: pubkey,
|
|
445
|
+
level: u64,
|
|
446
|
+
experience: u64,
|
|
447
|
+
health: u64,
|
|
448
|
+
position_x: u64,
|
|
449
|
+
position_y: u64,
|
|
450
|
+
inventory: [u64; 10],
|
|
451
|
+
is_active: bool
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
account GameWorld {
|
|
455
|
+
width: u64,
|
|
456
|
+
height: u64,
|
|
457
|
+
players_count: u64,
|
|
458
|
+
started_at: u64
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
instruction move_player(direction: string, distance: u64) {
|
|
462
|
+
let player = load_account<Player>(get_signer());
|
|
463
|
+
|
|
464
|
+
match direction {
|
|
465
|
+
"north" => player.position_y += distance,
|
|
466
|
+
"south" => player.position_y -= distance,
|
|
467
|
+
"east" => player.position_x += distance,
|
|
468
|
+
"west" => player.position_x -= distance,
|
|
469
|
+
_ => require(false, "Invalid direction")
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
// Validate bounds
|
|
473
|
+
let world = load_account<GameWorld>(0);
|
|
474
|
+
require(player.position_x < world.width, "Out of bounds");
|
|
475
|
+
require(player.position_y < world.height, "Out of bounds");
|
|
476
|
+
|
|
477
|
+
save_account(get_signer(), player);
|
|
478
|
+
emit PlayerMoved { player: get_signer(), x: player.position_x, y: player.position_y };
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
instruction level_up() {
|
|
482
|
+
let player = load_account<Player>(get_signer());
|
|
483
|
+
|
|
484
|
+
let required_exp = player.level * 100;
|
|
485
|
+
require(player.experience >= required_exp, "Insufficient experience");
|
|
486
|
+
|
|
487
|
+
player.level += 1;
|
|
488
|
+
player.experience -= required_exp;
|
|
489
|
+
player.health = 100; // Full heal on level up
|
|
490
|
+
|
|
491
|
+
save_account(get_signer(), player);
|
|
492
|
+
emit LevelUp { player: get_signer(), new_level: player.level };
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
event PlayerMoved {
|
|
496
|
+
player: pubkey,
|
|
497
|
+
x: u64,
|
|
498
|
+
y: u64
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
event LevelUp {
|
|
502
|
+
player: pubkey,
|
|
503
|
+
new_level: u64
|
|
504
|
+
}
|
|
505
|
+
`,
|
|
506
|
+
dao: `// DAO Governance on Five VM
|
|
507
|
+
script DAOGovernance {
|
|
508
|
+
init() {
|
|
509
|
+
log("DAO Governance initialized");
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
constraints {
|
|
513
|
+
// Validate governance token
|
|
514
|
+
let token_balance = get_token_balance();
|
|
515
|
+
require(token_balance > 0, "No governance tokens");
|
|
516
|
+
|
|
517
|
+
// Check proposal validity
|
|
518
|
+
let proposal_id = get_current_proposal();
|
|
519
|
+
if proposal_id > 0 {
|
|
520
|
+
let proposal = get_proposal(proposal_id);
|
|
521
|
+
require(proposal.is_active, "Proposal not active");
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
account Proposal {
|
|
527
|
+
id: u64,
|
|
528
|
+
title: string,
|
|
529
|
+
description: string,
|
|
530
|
+
proposer: pubkey,
|
|
531
|
+
votes_for: u64,
|
|
532
|
+
votes_against: u64,
|
|
533
|
+
start_time: u64,
|
|
534
|
+
end_time: u64,
|
|
535
|
+
is_active: bool,
|
|
536
|
+
is_executed: bool
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
account Vote {
|
|
540
|
+
proposal_id: u64,
|
|
541
|
+
voter: pubkey,
|
|
542
|
+
amount: u64,
|
|
543
|
+
is_for: bool
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
instruction create_proposal(title: string, description: string, duration: u64) -> u64 {
|
|
547
|
+
let proposer_balance = get_token_balance();
|
|
548
|
+
require(proposer_balance >= 1000, "Insufficient tokens to propose");
|
|
549
|
+
|
|
550
|
+
let proposal_id = get_next_proposal_id();
|
|
551
|
+
let current_time = get_clock().unix_timestamp;
|
|
552
|
+
|
|
553
|
+
let proposal = Proposal {
|
|
554
|
+
id: proposal_id,
|
|
555
|
+
title,
|
|
556
|
+
description,
|
|
557
|
+
proposer: get_signer(),
|
|
558
|
+
votes_for: 0,
|
|
559
|
+
votes_against: 0,
|
|
560
|
+
start_time: current_time,
|
|
561
|
+
end_time: current_time + duration,
|
|
562
|
+
is_active: true,
|
|
563
|
+
is_executed: false
|
|
564
|
+
};
|
|
565
|
+
|
|
566
|
+
create_account(derive_pda("proposal", [proposal_id]), proposal);
|
|
567
|
+
emit ProposalCreated { id: proposal_id, proposer: get_signer() };
|
|
568
|
+
|
|
569
|
+
proposal_id
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
instruction vote(proposal_id: u64, amount: u64, is_for: bool) {
|
|
573
|
+
let voter_balance = get_token_balance();
|
|
574
|
+
require(voter_balance >= amount, "Insufficient token balance");
|
|
575
|
+
|
|
576
|
+
let proposal = load_account<Proposal>(derive_pda("proposal", [proposal_id]));
|
|
577
|
+
require(proposal.is_active, "Proposal not active");
|
|
578
|
+
require(get_clock().unix_timestamp <= proposal.end_time, "Voting period ended");
|
|
579
|
+
|
|
580
|
+
// Check if already voted
|
|
581
|
+
let vote_account = derive_pda("vote", [proposal_id, get_signer()]);
|
|
582
|
+
require(!account_exists(vote_account), "Already voted");
|
|
583
|
+
|
|
584
|
+
// Record vote
|
|
585
|
+
let vote = Vote {
|
|
586
|
+
proposal_id,
|
|
587
|
+
voter: get_signer(),
|
|
588
|
+
amount,
|
|
589
|
+
is_for
|
|
590
|
+
};
|
|
591
|
+
|
|
592
|
+
create_account(vote_account, vote);
|
|
593
|
+
|
|
594
|
+
// Update proposal vote counts
|
|
595
|
+
if is_for {
|
|
596
|
+
proposal.votes_for += amount;
|
|
597
|
+
} else {
|
|
598
|
+
proposal.votes_against += amount;
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
save_account(derive_pda("proposal", [proposal_id]), proposal);
|
|
602
|
+
emit VoteCast { proposal_id, voter: get_signer(), amount, is_for };
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
event ProposalCreated {
|
|
606
|
+
id: u64,
|
|
607
|
+
proposer: pubkey
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
event VoteCast {
|
|
611
|
+
proposal_id: u64,
|
|
612
|
+
voter: pubkey,
|
|
613
|
+
amount: u64,
|
|
614
|
+
is_for: bool
|
|
615
|
+
}
|
|
616
|
+
`
|
|
617
|
+
};
|
|
618
|
+
return templates[template] || templates.basic;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Get template test file content
|
|
622
|
+
*/
|
|
623
|
+
function getTemplateTestFile(template) {
|
|
624
|
+
// Generate template-specific test functions
|
|
625
|
+
const templates = {
|
|
626
|
+
basic: `// Tests for ${template} template
|
|
627
|
+
// Use @test-params to specify function parameters for testing
|
|
628
|
+
// Format: @test-params <param1> <param2> ... <expected_result>
|
|
629
|
+
|
|
630
|
+
// @test-params 10 20 30
|
|
631
|
+
pub test_add(a: u64, b: u64) -> u64 {
|
|
632
|
+
return a + b;
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
// @test-params 5 2 10
|
|
636
|
+
pub test_multiply(a: u64, b: u64) -> u64 {
|
|
637
|
+
return a * b;
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
// @test-params
|
|
641
|
+
pub test_initialization() {
|
|
642
|
+
log("Initialization test passed");
|
|
643
|
+
}
|
|
644
|
+
`,
|
|
645
|
+
defi: `// Tests for ${template} template
|
|
646
|
+
// Test DeFi protocol functionality
|
|
647
|
+
|
|
648
|
+
// @test-params 1000 2000 3000
|
|
649
|
+
pub test_deposit(amount: u64) -> u64 {
|
|
650
|
+
// Simulate deposit logic
|
|
651
|
+
let fee = (amount * 1) / 100; // 1% fee
|
|
652
|
+
return amount - fee;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
// @test-params 100 50 50
|
|
656
|
+
pub test_swap_calculation(pool_a: u64, amount: u64) -> u64 {
|
|
657
|
+
// Swap calculation
|
|
658
|
+
let result = (amount * pool_a) / (pool_a + amount);
|
|
659
|
+
return result;
|
|
660
|
+
}
|
|
661
|
+
`,
|
|
662
|
+
nft: `// Tests for ${template} template
|
|
663
|
+
// Test NFT functionality
|
|
664
|
+
|
|
665
|
+
// @test-params
|
|
666
|
+
pub test_mint_nft() -> bool {
|
|
667
|
+
// Test NFT minting
|
|
668
|
+
log("NFT mint test passed");
|
|
669
|
+
return true;
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// @test-params
|
|
673
|
+
pub test_transfer_nft() -> bool {
|
|
674
|
+
// Test NFT transfer
|
|
675
|
+
log("NFT transfer test passed");
|
|
676
|
+
return true;
|
|
677
|
+
}
|
|
678
|
+
`,
|
|
679
|
+
game: `// Tests for ${template} template
|
|
680
|
+
// Test game logic
|
|
681
|
+
|
|
682
|
+
// @test-params 5 3 true
|
|
683
|
+
pub test_move_validation(x: u64, y: u64) -> bool {
|
|
684
|
+
// Validate game world bounds
|
|
685
|
+
let max_x = 100u64;
|
|
686
|
+
let max_y = 100u64;
|
|
687
|
+
return x < max_x && y < max_y;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
// @test-params 1 100 101
|
|
691
|
+
pub test_level_up(level: u64, experience: u64) -> u64 {
|
|
692
|
+
// Calculate experience needed for next level
|
|
693
|
+
let required_exp = level * 100;
|
|
694
|
+
if experience >= required_exp {
|
|
695
|
+
return level + 1;
|
|
696
|
+
}
|
|
697
|
+
return level;
|
|
698
|
+
}
|
|
699
|
+
`,
|
|
700
|
+
dao: `// Tests for ${template} template
|
|
701
|
+
// Test DAO governance
|
|
702
|
+
|
|
703
|
+
// @test-params 1000 50 true
|
|
704
|
+
pub test_vote_power(tokens: u64, vote_amount: u64) -> bool {
|
|
705
|
+
// Test vote power calculation
|
|
706
|
+
return vote_amount <= tokens;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
// @test-params 1000 600 true
|
|
710
|
+
pub test_proposal_threshold(token_balance: u64, threshold: u64) -> bool {
|
|
711
|
+
// Test if balance meets proposal threshold
|
|
712
|
+
return token_balance >= threshold;
|
|
713
|
+
}
|
|
714
|
+
`
|
|
715
|
+
};
|
|
716
|
+
return templates[template] || templates.basic;
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Generate README content
|
|
720
|
+
*/
|
|
721
|
+
function generateReadme(template) {
|
|
722
|
+
return `# Five VM Project
|
|
723
|
+
|
|
724
|
+
A ${template} project built with Five VM.
|
|
725
|
+
|
|
726
|
+
## Getting Started
|
|
727
|
+
|
|
728
|
+
### Prerequisites
|
|
729
|
+
|
|
730
|
+
- Node.js 18+
|
|
731
|
+
- Five CLI: \`npm install -g five-cli\`
|
|
732
|
+
|
|
733
|
+
### Building
|
|
734
|
+
|
|
735
|
+
\`\`\`bash
|
|
736
|
+
# Compile the project
|
|
737
|
+
npm run build
|
|
738
|
+
|
|
739
|
+
# Compile with optimizations
|
|
740
|
+
npm run build:release
|
|
741
|
+
|
|
742
|
+
# Compile with debug information
|
|
743
|
+
npm run build:debug
|
|
744
|
+
\`\`\`
|
|
745
|
+
|
|
746
|
+
### Testing
|
|
747
|
+
|
|
748
|
+
#### Discover and Run Tests
|
|
749
|
+
|
|
750
|
+
Five CLI automatically discovers test functions from your \`.v\` files:
|
|
751
|
+
|
|
752
|
+
\`\`\`bash
|
|
753
|
+
# Run all tests
|
|
754
|
+
npm test
|
|
755
|
+
|
|
756
|
+
# Run with watch mode for continuous testing
|
|
757
|
+
five test --watch
|
|
758
|
+
|
|
759
|
+
# Run specific tests by filter
|
|
760
|
+
five test --filter "test_add"
|
|
761
|
+
|
|
762
|
+
# Run with verbose output
|
|
763
|
+
five test --verbose
|
|
764
|
+
|
|
765
|
+
# Run with JSON output for CI/CD
|
|
766
|
+
five test --format json
|
|
767
|
+
\`\`\`
|
|
768
|
+
|
|
769
|
+
#### Writing Tests
|
|
770
|
+
|
|
771
|
+
Test functions in your \`.v\` files use the \`pub test_*\` naming convention and include \`@test-params\` comments:
|
|
772
|
+
|
|
773
|
+
\`\`\`v
|
|
774
|
+
// @test-params 10 20 30
|
|
775
|
+
pub test_add(a: u64, b: u64) -> u64 {
|
|
776
|
+
return a + b;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// @test-params 5 2 10
|
|
780
|
+
pub test_multiply(a: u64, b: u64) -> u64 {
|
|
781
|
+
return a * b;
|
|
782
|
+
}
|
|
783
|
+
\`\`\`
|
|
784
|
+
|
|
785
|
+
The \`@test-params\` comment specifies the parameters to pass and expected result. The test runner will:
|
|
786
|
+
1. Discover test functions automatically
|
|
787
|
+
2. Compile the source file
|
|
788
|
+
3. Execute with the specified parameters
|
|
789
|
+
4. Validate the result matches
|
|
790
|
+
|
|
791
|
+
### Development
|
|
792
|
+
|
|
793
|
+
\`\`\`bash
|
|
794
|
+
# Watch for changes and auto-compile
|
|
795
|
+
npm run watch
|
|
796
|
+
\`\`\`
|
|
797
|
+
|
|
798
|
+
### Deployment
|
|
799
|
+
|
|
800
|
+
\`\`\`bash
|
|
801
|
+
# Deploy to devnet
|
|
802
|
+
npm run deploy
|
|
803
|
+
\`\`\`
|
|
804
|
+
|
|
805
|
+
## Project Structure
|
|
806
|
+
|
|
807
|
+
- \`src/\` - Five VM source files (.v)
|
|
808
|
+
- \`tests/\` - Test files (.v files with test_* functions)
|
|
809
|
+
- \`build/\` - Compiled bytecode
|
|
810
|
+
- \`docs/\` - Documentation
|
|
811
|
+
- \`five.toml\` - Project configuration
|
|
812
|
+
|
|
813
|
+
## Multi-File Projects
|
|
814
|
+
|
|
815
|
+
If your project uses multiple modules with \`use\` or \`import\` statements, Five CLI automatically handles:
|
|
816
|
+
|
|
817
|
+
\`\`\`bash
|
|
818
|
+
# Automatic discovery of imported modules
|
|
819
|
+
five compile src/main.v --auto-discover
|
|
820
|
+
|
|
821
|
+
# Or use the build command which respects five.toml configuration
|
|
822
|
+
five build
|
|
823
|
+
\`\`\`
|
|
824
|
+
|
|
825
|
+
## Learn More
|
|
826
|
+
|
|
827
|
+
- [Five VM Documentation](https://five-vm.dev)
|
|
828
|
+
- [Five VM GitHub](https://github.com/five-vm)
|
|
829
|
+
- [Multi-File Compilation Guide](./docs/multi-file.md)
|
|
830
|
+
- [Examples](./examples)
|
|
831
|
+
|
|
832
|
+
## License
|
|
833
|
+
|
|
834
|
+
MIT
|
|
835
|
+
`;
|
|
836
|
+
}
|
|
837
|
+
/**
|
|
838
|
+
* Generate .gitignore content
|
|
839
|
+
*/
|
|
840
|
+
function generateGitignore() {
|
|
841
|
+
return `# Build outputs
|
|
842
|
+
build/
|
|
843
|
+
*.bin
|
|
844
|
+
*.so
|
|
845
|
+
*.wasm
|
|
846
|
+
|
|
847
|
+
# Node.js
|
|
848
|
+
node_modules/
|
|
849
|
+
npm-debug.log*
|
|
850
|
+
yarn-debug.log*
|
|
851
|
+
yarn-error.log*
|
|
852
|
+
|
|
853
|
+
# Environment variables
|
|
854
|
+
.env
|
|
855
|
+
.env.local
|
|
856
|
+
|
|
857
|
+
# IDE
|
|
858
|
+
.vscode/
|
|
859
|
+
.idea/
|
|
860
|
+
*.swp
|
|
861
|
+
*.swo
|
|
862
|
+
|
|
863
|
+
# OS
|
|
864
|
+
.DS_Store
|
|
865
|
+
Thumbs.db
|
|
866
|
+
|
|
867
|
+
# Five VM
|
|
868
|
+
.five/cache/
|
|
869
|
+
*.debug.bin
|
|
870
|
+
`;
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Display success message
|
|
874
|
+
*/
|
|
875
|
+
function displaySuccessMessage(projectDir, projectName, options) {
|
|
876
|
+
console.log('\n' + uiSuccess('Project initialized'));
|
|
877
|
+
console.log('\n' + chalk.bold('Next steps:'));
|
|
878
|
+
if (projectDir !== process.cwd()) {
|
|
879
|
+
console.log(` ${uiColors.info('cd')} ${projectDir}`);
|
|
880
|
+
}
|
|
881
|
+
console.log(` ${uiColors.info('npm install')} - Install dependencies`);
|
|
882
|
+
console.log(` ${uiColors.info('npm run build')} - Compile the project`);
|
|
883
|
+
console.log(` ${uiColors.info('npm test')} - Run tests`);
|
|
884
|
+
console.log(` ${uiColors.info('npm run watch')} - Start development mode`);
|
|
885
|
+
console.log('\n' + uiColors.muted('Happy coding with Five VM.'));
|
|
886
|
+
}
|
|
887
|
+
//# sourceMappingURL=init.js.map
|