@5ive-tech/cli 1.0.15 → 1.0.16
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/package.json +1 -1
- package/templates/AGENTS.md +541 -83
package/package.json
CHANGED
package/templates/AGENTS.md
CHANGED
|
@@ -31,69 +31,17 @@ Never rely on stale docs when behavior is high-stakes (deploy/execute/CPI encodi
|
|
|
31
31
|
5. Execute and verify confirmed tx metadata (`meta.err == null`).
|
|
32
32
|
6. Record signatures + compute units.
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
Use this profile unless you have direct proof in your current compiler version that a broader syntax feature is stable.
|
|
37
|
-
|
|
38
|
-
1. Prefer top-level accounts + top-level functions. Do not wrap programs in `script Name { ... }`.
|
|
39
|
-
2. Use account/signer/mut attributes in this order style:
|
|
40
|
-
- `owner: pubkey @signer`
|
|
41
|
-
- `state: Mint @mut`
|
|
42
|
-
- `ata: TokenAccount @mut @init`
|
|
43
|
-
3. Prefer plain function declarations like:
|
|
44
|
-
- `pub transfer(...) { ... }`
|
|
45
|
-
- `pub mint_to(...) { ... }`
|
|
46
|
-
4. Any function intended to be called via `5ive execute` must be declared `pub`.
|
|
47
|
-
5. Keep logic to `require`, `if/else`, arithmetic, assignments, and simple returns.
|
|
48
|
-
6. Validate after every meaningful edit:
|
|
49
|
-
- `5ive compile src/main.v -o build/main.five`
|
|
50
|
-
|
|
51
|
-
Avoid these patterns by default (high-risk for invalid output in agent-generated code):
|
|
52
|
-
1. `instruction ...` function form
|
|
53
|
-
2. Attribute-first parameters like `@signer owner: pubkey`
|
|
54
|
-
3. Optional parameters/fields in signatures (`x?: T`) and nullish expressions (`??`)
|
|
55
|
-
4. `enum`/`event` heavy first-pass contracts
|
|
56
|
-
5. Event emission (`event` / `emit`) unless you have compile+runtime proof in your current toolchain
|
|
57
|
-
6. Unverified literals/helpers like `pubkey(0)` unless confirmed in working examples
|
|
58
|
-
7. Parser-only/experimental syntax from tokenizer docs without a compile-verified example
|
|
59
|
-
|
|
60
|
-
Safe token-style baseline:
|
|
61
|
-
```v
|
|
62
|
-
account Mint {
|
|
63
|
-
authority: pubkey;
|
|
64
|
-
supply: u64;
|
|
65
|
-
decimals: u8;
|
|
66
|
-
}
|
|
34
|
+
### 3.1 Strict Authoring Rules
|
|
67
35
|
|
|
68
|
-
|
|
69
|
-
owner_key: pubkey;
|
|
70
|
-
mint: pubkey;
|
|
71
|
-
bal: u64;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
pub init_mint(
|
|
75
|
-
state: Mint @mut,
|
|
76
|
-
authority: pubkey @signer,
|
|
77
|
-
decimals: u8
|
|
78
|
-
) {
|
|
79
|
-
state.authority = authority;
|
|
80
|
-
state.supply = 0;
|
|
81
|
-
state.decimals = decimals;
|
|
82
|
-
}
|
|
36
|
+
These rules are non-negotiable and prevent the most common compilation failures:
|
|
83
37
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
require(source.mint == destination.mint, "mint mismatch");
|
|
92
|
-
require(source.bal >= amount, "insufficient funds");
|
|
93
|
-
source.bal = source.bal - amount;
|
|
94
|
-
destination.bal = destination.bal + amount;
|
|
95
|
-
}
|
|
96
|
-
```
|
|
38
|
+
1. **All account fields must end with `;`** — missing semicolons cause parser failure.
|
|
39
|
+
2. **Use `account @signer` for authorization** — not `pubkey @signer`. This preserves the `.key` accessor.
|
|
40
|
+
3. **Use `.key` on `account`-typed parameters** to extract public keys for comparisons and assignments.
|
|
41
|
+
4. **Use `-> ReturnType` for functions with return values** — e.g. `-> u64`, `-> pubkey`, `-> bool`.
|
|
42
|
+
5. **`pubkey(0)` and `0` are valid** for zero-initializing pubkey fields (disabling authorities).
|
|
43
|
+
6. **`string<N>` is production-safe** — use freely in accounts and function parameters.
|
|
44
|
+
7. **All comparison operators work in `require()`** — `==`, `!=`, `<`, `<=`, `>`, `>=`, `!`.
|
|
97
45
|
|
|
98
46
|
## 4) DSL Feature Inventory (Deep)
|
|
99
47
|
|
|
@@ -101,7 +49,7 @@ This section enumerates language features discovered from parser/compiler code a
|
|
|
101
49
|
|
|
102
50
|
### 4.1 Top-level declarations
|
|
103
51
|
Observed and/or parsed:
|
|
104
|
-
1. `account Name { ... }`
|
|
52
|
+
1. `account Name { ... }` — **all fields must be terminated with `;`**
|
|
105
53
|
2. Global fields/variables (including `mut`)
|
|
106
54
|
3. `init { ... }` block
|
|
107
55
|
4. `constraints { ... }` block
|
|
@@ -111,6 +59,21 @@ Observed and/or parsed:
|
|
|
111
59
|
8. `use` / `import` statements
|
|
112
60
|
9. Legacy `script Name { ... }` wrapper (parser-supported)
|
|
113
61
|
|
|
62
|
+
```v
|
|
63
|
+
// ✅ CORRECT — semicolons required
|
|
64
|
+
account Mint {
|
|
65
|
+
authority: pubkey;
|
|
66
|
+
supply: u64;
|
|
67
|
+
decimals: u8;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// ❌ WRONG — parser failure
|
|
71
|
+
account Mint {
|
|
72
|
+
authority: pubkey
|
|
73
|
+
supply: u64
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
114
77
|
### 4.2 Function definition forms
|
|
115
78
|
Parser accepts flexible forms:
|
|
116
79
|
1. `pub add(...) -> ... { ... }`
|
|
@@ -141,11 +104,28 @@ Common attributes:
|
|
|
141
104
|
|
|
142
105
|
Examples also show legacy bracket seed forms after `@init`.
|
|
143
106
|
|
|
107
|
+
**Attribute stacking order for account parameters (empirically verified):**
|
|
108
|
+
|
|
109
|
+
```
|
|
110
|
+
Type @mut @init(payer=name, space=bytes) @signer
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
Example:
|
|
114
|
+
```v
|
|
115
|
+
pub init_mint(
|
|
116
|
+
mint_account: Mint @mut @init(payer=authority, space=256) @signer,
|
|
117
|
+
authority: account @mut @signer,
|
|
118
|
+
...
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
Order: (1) Type declaration → (2) `@mut` → (3) `@init(...)` → (4) `@signer`.
|
|
123
|
+
|
|
144
124
|
### 4.5 Types
|
|
145
125
|
Supported/parsed type families:
|
|
146
126
|
1. Primitive numeric/bool/pubkey/string types (`u8..u128`, `i8..i64`, `bool`, `pubkey`, `string`)
|
|
147
127
|
2. `Account` type and account-typed params
|
|
148
|
-
3. Sized strings: `string<
|
|
128
|
+
3. **Sized strings: `string<N>`** — production-safe, use in accounts and function parameters
|
|
149
129
|
4. Arrays:
|
|
150
130
|
- Rust style: `[T; N]`
|
|
151
131
|
- TypeScript-style sized: `T[N]`
|
|
@@ -158,20 +138,29 @@ Supported/parsed type families:
|
|
|
158
138
|
- nested generics (`Option<Option<u64>>` etc.)
|
|
159
139
|
8. Namespaced/custom types: `module::Type`
|
|
160
140
|
9. Optional account fields in structs/accounts: `field?: Type`
|
|
141
|
+
10. **`pubkey(0)` and integer `0`** — valid for zero-initialization of pubkey fields (interchangeable)
|
|
161
142
|
|
|
162
143
|
### 4.6 Statements
|
|
163
144
|
Observed and parser-supported:
|
|
164
145
|
1. `let` declarations (with `mut` and optional type annotation)
|
|
146
|
+
- Type inference works: `let is_owner = source.owner == authority.key;` infers `bool`
|
|
147
|
+
- Use `let` without explicit annotation for boolean and scalar expressions
|
|
165
148
|
2. Assignment:
|
|
166
149
|
- direct: `x = y`
|
|
167
150
|
- compound: `+=`, `-=`, `*=`, `/=`, `<<=`, `>>=`, `&=`, `|=`, `^=`
|
|
168
151
|
3. Field assignment: `obj.field = value`
|
|
169
|
-
4. Return statements (`return`, `return value`)
|
|
170
|
-
5. Guard/assertion: `require(condition)`
|
|
152
|
+
4. Return statements (`return`, `return value`) — see §4.13 for return type syntax
|
|
153
|
+
5. Guard/assertion: `require(condition)` — **all operators verified:**
|
|
154
|
+
- Comparison: `==`, `!=`, `<`, `<=`, `>`, `>=`
|
|
155
|
+
- Boolean negation: `!expr`
|
|
156
|
+
- Logical: `&&`, `||`
|
|
157
|
+
- Example: `require(source.balance >= amount);`
|
|
158
|
+
- Example: `require(!account.is_frozen);`
|
|
171
159
|
6. Conditionals:
|
|
172
160
|
- `if (...) {}`
|
|
173
161
|
- `else if (...) {}`
|
|
174
162
|
- `else {}`
|
|
163
|
+
- Conditionals support nested `require()` statements and multiple assignments in both branches
|
|
175
164
|
7. Pattern matching: `match expr { ... }`, with optional arm guards (`if ...`)
|
|
176
165
|
8. Loops:
|
|
177
166
|
- `while (...) { ... }`
|
|
@@ -268,24 +257,64 @@ From tokenizer/parser support:
|
|
|
268
257
|
|
|
269
258
|
Repository tests also use comment-based param conventions (`// @test-params ...`) in many scripts.
|
|
270
259
|
|
|
271
|
-
### 4.12 Blockchain-oriented built-ins
|
|
272
|
-
|
|
260
|
+
### 4.12 Blockchain-oriented built-ins
|
|
261
|
+
Core built-ins available in all contracts:
|
|
273
262
|
1. `derive_pda(...)` (including bump-return and bump-specified variants)
|
|
274
263
|
2. `get_clock()`
|
|
275
264
|
3. `get_key(...)`
|
|
276
|
-
4.
|
|
265
|
+
4. **Account key access: `param.key`** — **core pattern for all `account`-typed parameters.** Use `.key` to extract pubkeys for comparisons and assignments.
|
|
266
|
+
|
|
267
|
+
```v
|
|
268
|
+
pub action(
|
|
269
|
+
state: MyAccount @mut,
|
|
270
|
+
caller: account @signer,
|
|
271
|
+
...
|
|
272
|
+
) {
|
|
273
|
+
require(state.authority == caller.key); // ownership check
|
|
274
|
+
state.last_actor = caller.key; // record who acted
|
|
275
|
+
}
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
5. **Authority revocation pattern:** assign `0` to any pubkey field to permanently disable it.
|
|
279
|
+
```v
|
|
280
|
+
state.authority = 0; // revokes authority — irreversible
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
### 4.13 Return types and values
|
|
284
|
+
Functions can declare return types with `->` syntax:
|
|
285
|
+
|
|
286
|
+
```v
|
|
287
|
+
pub get_value(state: MyAccount) -> u64 {
|
|
288
|
+
return state.amount;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
pub initialize(
|
|
292
|
+
state: MyAccount @mut @init(payer=creator, space=256) @signer,
|
|
293
|
+
creator: account @mut @signer,
|
|
294
|
+
...
|
|
295
|
+
) -> pubkey {
|
|
296
|
+
state.authority = creator.key;
|
|
297
|
+
return state.key;
|
|
298
|
+
}
|
|
299
|
+
```
|
|
277
300
|
|
|
278
|
-
|
|
301
|
+
Confirmed return types: `u8`, `u16`, `u32`, `u64`, `u128`, `i8`..`i64`, `bool`, `pubkey`.
|
|
279
302
|
|
|
280
303
|
## 5) Feature Maturity Matrix (Agent Safety)
|
|
281
304
|
|
|
282
305
|
### 5.1 Generally production-oriented (widely used in templates)
|
|
283
|
-
1. Accounts, `@mut`, `@signer`, `@init`
|
|
284
|
-
2. `require`
|
|
285
|
-
3. Basic control flow (`if`, `while`)
|
|
306
|
+
1. Accounts, `@mut`, `@signer`, `@init` (with attribute stacking)
|
|
307
|
+
2. `require` with all comparison operators (`==`, `!=`, `<`, `<=`, `>`, `>=`, `!`)
|
|
308
|
+
3. Basic control flow (`if`, `else`, `while`) with nested logic
|
|
286
309
|
4. Arithmetic/comparison/boolean expressions
|
|
287
310
|
5. `.five` compile/deploy/execute path
|
|
288
311
|
6. `interface` + explicit discriminator + explicit serializer CPI patterns
|
|
312
|
+
7. Return type declarations (`-> Type`) with `return value;`
|
|
313
|
+
8. `string<N>` fixed-size strings in accounts and parameters
|
|
314
|
+
9. `account.key` extraction from `account`-typed parameters
|
|
315
|
+
10. Authority disabling via `0` assignment to pubkey fields
|
|
316
|
+
11. `let` with type inference for scalar/boolean expressions
|
|
317
|
+
12. `pubkey(0)` zero-initialization
|
|
289
318
|
|
|
290
319
|
### 5.2 Available but validate per-version before critical use
|
|
291
320
|
1. Match expressions with `Option`/`Result`
|
|
@@ -406,18 +435,205 @@ const program = FiveProgram.fromABI("<SCRIPT_ACCOUNT>", abi, {
|
|
|
406
435
|
3. Surface signatures, CU metrics, and rich error states.
|
|
407
436
|
4. Use LSP-backed editing where available to reduce DSL mistakes.
|
|
408
437
|
|
|
409
|
-
## 10) Pattern
|
|
438
|
+
## 10) Contract Pattern Recipes
|
|
439
|
+
|
|
440
|
+
This section provides composable patterns for the most common contract archetypes. When building a novel contract, identify which patterns apply and combine them.
|
|
441
|
+
|
|
442
|
+
### 10.1 Authority-Gated State (Vault, Treasury, Config)
|
|
443
|
+
|
|
444
|
+
Core pattern: one or more pubkey fields control who can mutate state. Used in almost every contract.
|
|
445
|
+
|
|
446
|
+
```v
|
|
447
|
+
account Config {
|
|
448
|
+
authority: pubkey;
|
|
449
|
+
value: u64;
|
|
450
|
+
is_locked: bool;
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
pub update_value(
|
|
454
|
+
config: Config @mut,
|
|
455
|
+
authority: account @signer,
|
|
456
|
+
new_value: u64
|
|
457
|
+
) {
|
|
458
|
+
require(config.authority == authority.key);
|
|
459
|
+
require(!config.is_locked);
|
|
460
|
+
config.value = new_value;
|
|
461
|
+
}
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
**Key ingredients:** ownership check via `.key`, boolean guard with `!`, field mutation.
|
|
465
|
+
|
|
466
|
+
### 10.2 Custody & Withdraw (Vault, Staking)
|
|
467
|
+
|
|
468
|
+
Core pattern: deposit into an account, enforce balance invariants on withdraw.
|
|
469
|
+
|
|
470
|
+
```v
|
|
471
|
+
pub deposit(
|
|
472
|
+
vault: VaultAccount @mut,
|
|
473
|
+
depositor: account @signer,
|
|
474
|
+
amount: u64
|
|
475
|
+
) {
|
|
476
|
+
require(amount > 0);
|
|
477
|
+
vault.balance = vault.balance + amount;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
pub withdraw(
|
|
481
|
+
vault: VaultAccount @mut,
|
|
482
|
+
authority: account @signer,
|
|
483
|
+
amount: u64
|
|
484
|
+
) {
|
|
485
|
+
require(vault.authority == authority.key);
|
|
486
|
+
require(vault.balance >= amount);
|
|
487
|
+
require(amount > 0);
|
|
488
|
+
vault.balance = vault.balance - amount;
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
**Key ingredients:** `>= amount` balance guard, arithmetic on fields, `> 0` zero-amount prevention.
|
|
493
|
+
|
|
494
|
+
### 10.3 Lifecycle State Machine (Escrow, Auction, Proposal)
|
|
495
|
+
|
|
496
|
+
Core pattern: a status field controls which operations are valid. Transitions are guarded.
|
|
497
|
+
|
|
498
|
+
```v
|
|
499
|
+
account Escrow {
|
|
500
|
+
seller: pubkey;
|
|
501
|
+
buyer: pubkey;
|
|
502
|
+
amount: u64;
|
|
503
|
+
status: u8; // 0=open, 1=funded, 2=released, 3=cancelled
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
pub fund_escrow(
|
|
507
|
+
escrow: Escrow @mut,
|
|
508
|
+
buyer: account @signer,
|
|
509
|
+
amount: u64
|
|
510
|
+
) {
|
|
511
|
+
require(escrow.buyer == buyer.key);
|
|
512
|
+
require(escrow.status == 0);
|
|
513
|
+
require(amount == escrow.amount);
|
|
514
|
+
escrow.status = 1;
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
pub release_escrow(
|
|
518
|
+
escrow: Escrow @mut,
|
|
519
|
+
buyer: account @signer
|
|
520
|
+
) {
|
|
521
|
+
require(escrow.buyer == buyer.key);
|
|
522
|
+
require(escrow.status == 1);
|
|
523
|
+
escrow.status = 2;
|
|
524
|
+
}
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
**Key ingredients:** integer status field with `==` checks for state transitions, dual-party authorization.
|
|
528
|
+
|
|
529
|
+
### 10.4 Supply Accounting (Token, Mint, Points)
|
|
530
|
+
|
|
531
|
+
Core pattern: a central supply counter stays synchronized with distributed balances.
|
|
532
|
+
|
|
533
|
+
```v
|
|
534
|
+
pub mint_to(
|
|
535
|
+
supply_state: SupplyAccount @mut,
|
|
536
|
+
destination: BalanceAccount @mut,
|
|
537
|
+
authority: account @signer,
|
|
538
|
+
amount: u64
|
|
539
|
+
) {
|
|
540
|
+
require(supply_state.authority == authority.key);
|
|
541
|
+
require(amount > 0);
|
|
542
|
+
supply_state.total_supply = supply_state.total_supply + amount;
|
|
543
|
+
destination.balance = destination.balance + amount;
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
pub burn(
|
|
547
|
+
supply_state: SupplyAccount @mut,
|
|
548
|
+
source: BalanceAccount @mut,
|
|
549
|
+
owner: account @signer,
|
|
550
|
+
amount: u64
|
|
551
|
+
) {
|
|
552
|
+
require(source.owner == owner.key);
|
|
553
|
+
require(source.balance >= amount);
|
|
554
|
+
source.balance = source.balance - amount;
|
|
555
|
+
supply_state.total_supply = supply_state.total_supply - amount;
|
|
556
|
+
}
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
**Key ingredients:** paired increment/decrement across two accounts, conservation invariant.
|
|
560
|
+
|
|
561
|
+
### 10.5 Delegation & Approval (Token, DAO, Proxy)
|
|
562
|
+
|
|
563
|
+
Core pattern: an owner grants limited permissions to a delegate.
|
|
564
|
+
|
|
565
|
+
```v
|
|
566
|
+
pub approve(
|
|
567
|
+
state: DelegableAccount @mut,
|
|
568
|
+
owner: account @signer,
|
|
569
|
+
delegate: pubkey,
|
|
570
|
+
limit: u64
|
|
571
|
+
) {
|
|
572
|
+
require(state.owner == owner.key);
|
|
573
|
+
state.delegate = delegate;
|
|
574
|
+
state.delegated_limit = limit;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
pub revoke(
|
|
578
|
+
state: DelegableAccount @mut,
|
|
579
|
+
owner: account @signer
|
|
580
|
+
) {
|
|
581
|
+
require(state.owner == owner.key);
|
|
582
|
+
state.delegate = 0;
|
|
583
|
+
state.delegated_limit = 0;
|
|
584
|
+
}
|
|
585
|
+
```
|
|
586
|
+
|
|
587
|
+
**Key ingredients:** delegate pubkey field, limit tracking, zero-assignment to revoke.
|
|
588
|
+
|
|
589
|
+
### 10.6 Conservation Math (AMM, Orderbook, Settlement)
|
|
410
590
|
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
591
|
+
Core pattern: total value across accounts must remain constant.
|
|
592
|
+
|
|
593
|
+
```v
|
|
594
|
+
pub swap(
|
|
595
|
+
pool_a: PoolAccount @mut,
|
|
596
|
+
pool_b: PoolAccount @mut,
|
|
597
|
+
user_a: UserAccount @mut,
|
|
598
|
+
user_b: UserAccount @mut,
|
|
599
|
+
trader: account @signer,
|
|
600
|
+
amount_in: u64
|
|
601
|
+
) {
|
|
602
|
+
require(user_a.owner == trader.key);
|
|
603
|
+
require(user_a.balance >= amount_in);
|
|
604
|
+
require(amount_in > 0);
|
|
605
|
+
let amount_out = (pool_b.reserve * amount_in) / (pool_a.reserve + amount_in);
|
|
606
|
+
require(amount_out > 0);
|
|
607
|
+
user_a.balance = user_a.balance - amount_in;
|
|
608
|
+
pool_a.reserve = pool_a.reserve + amount_in;
|
|
609
|
+
pool_b.reserve = pool_b.reserve - amount_out;
|
|
610
|
+
user_b.balance = user_b.balance + amount_out;
|
|
611
|
+
}
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
**Key ingredients:** `let` with computed expression, multi-account mutation, balance checks on both sides.
|
|
615
|
+
|
|
616
|
+
### 10.7 Threshold & Risk Checks (Lending, Collateral, Liquidation)
|
|
617
|
+
|
|
618
|
+
Core pattern: actions gated by ratio or threshold comparisons.
|
|
619
|
+
|
|
620
|
+
```v
|
|
621
|
+
pub borrow(
|
|
622
|
+
position: LoanPosition @mut,
|
|
623
|
+
borrower: account @signer,
|
|
624
|
+
collateral_value: u64,
|
|
625
|
+
borrow_amount: u64
|
|
626
|
+
) {
|
|
627
|
+
require(position.owner == borrower.key);
|
|
628
|
+
require(borrow_amount > 0);
|
|
629
|
+
// Enforce 150% collateral ratio: collateral * 100 >= total_debt * 150
|
|
630
|
+
let new_debt = position.debt + borrow_amount;
|
|
631
|
+
require(collateral_value * 100 >= new_debt * 150);
|
|
632
|
+
position.debt = new_debt;
|
|
633
|
+
}
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
**Key ingredients:** `let` for intermediate computation, integer math for ratio checks, compound conditions.
|
|
421
637
|
|
|
422
638
|
## 11) Mainnet Safety Policy
|
|
423
639
|
|
|
@@ -464,3 +680,245 @@ Complete means:
|
|
|
464
680
|
3. Avoid hidden defaults for deploy/CPI critical parameters.
|
|
465
681
|
4. Keep changes auditable and reproducible.
|
|
466
682
|
5. If uncertain, inspect compiler/CLI source directly.
|
|
683
|
+
|
|
684
|
+
## 15) Agent One-Shot Contract Generation Procedure
|
|
685
|
+
|
|
686
|
+
Follow this procedure to produce correct 5IVE contracts on first compilation, regardless of contract type.
|
|
687
|
+
|
|
688
|
+
### Step 1: Define account schemas
|
|
689
|
+
- Identify every distinct on-chain state object your contract needs.
|
|
690
|
+
- Each gets an `account Name { ... }` block with **all fields terminated by `;`**.
|
|
691
|
+
- Choose field types from: `pubkey`, `u8`–`u128`, `i8`–`i64`, `bool`, `string<N>`.
|
|
692
|
+
- Include an `authority: pubkey;` field on any account that needs access control.
|
|
693
|
+
- Include a `status: u8;` field for lifecycle/state-machine accounts.
|
|
694
|
+
|
|
695
|
+
### Step 2: Define initializer functions
|
|
696
|
+
- For each account that users create at runtime, write an `init_*` function.
|
|
697
|
+
- The account parameter uses the full attribute stack: `Type @mut @init(payer=name, space=bytes) @signer`.
|
|
698
|
+
- The payer is `account @mut @signer`.
|
|
699
|
+
- Set every field to a known value (don't leave uninitialized fields).
|
|
700
|
+
- Return `-> pubkey` with `return account.key;` when callers need the address.
|
|
701
|
+
|
|
702
|
+
### Step 3: Define action functions
|
|
703
|
+
- Every state-mutating function takes the relevant account(s) as `AccountType @mut`.
|
|
704
|
+
- Authorization: take an `account @signer` parameter, then `require(state.authority == signer.key);`.
|
|
705
|
+
- Guards: use `require()` with any comparison operator (`==`, `!=`, `<`, `<=`, `>`, `>=`, `!`).
|
|
706
|
+
- For balance operations: always check `require(source.balance >= amount);` before subtraction.
|
|
707
|
+
- For state machines: check `require(state.status == EXPECTED_STATUS);` before transition.
|
|
708
|
+
- Use `let` for intermediate computations (type inference handles it).
|
|
709
|
+
|
|
710
|
+
### Step 4: Define read/query functions
|
|
711
|
+
- Use `-> ReturnType` syntax for functions that return values.
|
|
712
|
+
- `return state.field;` to return account data.
|
|
713
|
+
|
|
714
|
+
### Step 5: Compile and verify
|
|
715
|
+
- Run `5ive build` or `5ive compile src/main.v -o build/main.five`.
|
|
716
|
+
- Fix any parser errors (most common: missing `;` in account fields).
|
|
717
|
+
|
|
718
|
+
### Syntax quick-reference
|
|
719
|
+
|
|
720
|
+
| Pattern | Syntax |
|
|
721
|
+
|---|---|
|
|
722
|
+
| Account field | `name: type;` (semicolon required) |
|
|
723
|
+
| Init parameter | `acc: Type @mut @init(payer=p, space=N) @signer` |
|
|
724
|
+
| Signer parameter | `caller: account @signer` or `caller: account @mut @signer` |
|
|
725
|
+
| Ownership check | `require(state.authority == caller.key);` |
|
|
726
|
+
| Balance guard | `require(state.balance >= amount);` |
|
|
727
|
+
| Boolean guard | `require(!state.is_locked);` |
|
|
728
|
+
| Zero-amount guard | `require(amount > 0);` |
|
|
729
|
+
| Revoke authority | `state.authority = 0;` |
|
|
730
|
+
| Status transition | `state.status = 1;` |
|
|
731
|
+
| Local variable | `let x = expr;` |
|
|
732
|
+
| Return value | `pub fn(...) -> u64 { return state.value; }` |
|
|
733
|
+
| Fixed string field | `name: string<32>;` |
|
|
734
|
+
| Zero-init pubkey | `state.delegate = 0;` or `state.delegate = pubkey(0);` |
|
|
735
|
+
|
|
736
|
+
## 16) Reference Implementations
|
|
737
|
+
|
|
738
|
+
Three verified, compilable patterns covering distinct contract archetypes. Use as canonical references.
|
|
739
|
+
|
|
740
|
+
### 16.1 Token (Supply Accounting + Delegation + Freeze)
|
|
741
|
+
|
|
742
|
+
```v
|
|
743
|
+
account Mint {
|
|
744
|
+
authority: pubkey;
|
|
745
|
+
freeze_authority: pubkey;
|
|
746
|
+
supply: u64;
|
|
747
|
+
decimals: u8;
|
|
748
|
+
name: string<32>;
|
|
749
|
+
symbol: string<32>;
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
account TokenAccount {
|
|
753
|
+
owner: pubkey;
|
|
754
|
+
mint: pubkey;
|
|
755
|
+
balance: u64;
|
|
756
|
+
is_frozen: bool;
|
|
757
|
+
delegate: pubkey;
|
|
758
|
+
delegated_amount: u64;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
pub init_mint(
|
|
762
|
+
mint_account: Mint @mut @init(payer=authority, space=256) @signer,
|
|
763
|
+
authority: account @mut @signer,
|
|
764
|
+
freeze_authority: pubkey,
|
|
765
|
+
decimals: u8,
|
|
766
|
+
name: string<32>,
|
|
767
|
+
symbol: string<32>
|
|
768
|
+
) -> pubkey {
|
|
769
|
+
require(decimals <= 20);
|
|
770
|
+
mint_account.authority = authority.key;
|
|
771
|
+
mint_account.freeze_authority = freeze_authority;
|
|
772
|
+
mint_account.supply = 0;
|
|
773
|
+
mint_account.decimals = decimals;
|
|
774
|
+
mint_account.name = name;
|
|
775
|
+
mint_account.symbol = symbol;
|
|
776
|
+
return mint_account.key;
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
pub transfer(
|
|
780
|
+
source: TokenAccount @mut,
|
|
781
|
+
destination: TokenAccount @mut,
|
|
782
|
+
owner: account @signer,
|
|
783
|
+
amount: u64
|
|
784
|
+
) {
|
|
785
|
+
require(source.owner == owner.key);
|
|
786
|
+
require(source.balance >= amount);
|
|
787
|
+
require(source.mint == destination.mint);
|
|
788
|
+
require(!source.is_frozen);
|
|
789
|
+
require(!destination.is_frozen);
|
|
790
|
+
require(amount > 0);
|
|
791
|
+
source.balance = source.balance - amount;
|
|
792
|
+
destination.balance = destination.balance + amount;
|
|
793
|
+
}
|
|
794
|
+
|
|
795
|
+
pub approve(
|
|
796
|
+
source: TokenAccount @mut,
|
|
797
|
+
owner: account @signer,
|
|
798
|
+
delegate: pubkey,
|
|
799
|
+
amount: u64
|
|
800
|
+
) {
|
|
801
|
+
require(source.owner == owner.key);
|
|
802
|
+
source.delegate = delegate;
|
|
803
|
+
source.delegated_amount = amount;
|
|
804
|
+
}
|
|
805
|
+
```
|
|
806
|
+
|
|
807
|
+
**Patterns exercised:** `@init` stacking, supply accounting, freeze guards, delegation, `.key` extraction, `string<N>`, `-> pubkey` return.
|
|
808
|
+
|
|
809
|
+
### 16.2 Vault (Custody + Authority Gating)
|
|
810
|
+
|
|
811
|
+
```v
|
|
812
|
+
account Vault {
|
|
813
|
+
authority: pubkey;
|
|
814
|
+
balance: u64;
|
|
815
|
+
is_locked: bool;
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
pub init_vault(
|
|
819
|
+
vault: Vault @mut @init(payer=creator, space=128) @signer,
|
|
820
|
+
creator: account @mut @signer
|
|
821
|
+
) -> pubkey {
|
|
822
|
+
vault.authority = creator.key;
|
|
823
|
+
vault.balance = 0;
|
|
824
|
+
vault.is_locked = false;
|
|
825
|
+
return vault.key;
|
|
826
|
+
}
|
|
827
|
+
|
|
828
|
+
pub deposit(
|
|
829
|
+
vault: Vault @mut,
|
|
830
|
+
depositor: account @signer,
|
|
831
|
+
amount: u64
|
|
832
|
+
) {
|
|
833
|
+
require(!vault.is_locked);
|
|
834
|
+
require(amount > 0);
|
|
835
|
+
vault.balance = vault.balance + amount;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
pub withdraw(
|
|
839
|
+
vault: Vault @mut,
|
|
840
|
+
authority: account @signer,
|
|
841
|
+
amount: u64
|
|
842
|
+
) {
|
|
843
|
+
require(vault.authority == authority.key);
|
|
844
|
+
require(!vault.is_locked);
|
|
845
|
+
require(vault.balance >= amount);
|
|
846
|
+
require(amount > 0);
|
|
847
|
+
vault.balance = vault.balance - amount;
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
pub lock_vault(
|
|
851
|
+
vault: Vault @mut,
|
|
852
|
+
authority: account @signer
|
|
853
|
+
) {
|
|
854
|
+
require(vault.authority == authority.key);
|
|
855
|
+
vault.is_locked = true;
|
|
856
|
+
}
|
|
857
|
+
|
|
858
|
+
pub transfer_authority(
|
|
859
|
+
vault: Vault @mut,
|
|
860
|
+
current_authority: account @signer,
|
|
861
|
+
new_authority: pubkey
|
|
862
|
+
) {
|
|
863
|
+
require(vault.authority == current_authority.key);
|
|
864
|
+
vault.authority = new_authority;
|
|
865
|
+
}
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
**Patterns exercised:** authority gating, boolean lock, balance guards, authority transfer, `@init` stacking.
|
|
869
|
+
|
|
870
|
+
### 16.3 Escrow (Lifecycle State Machine + Dual-Party Auth)
|
|
871
|
+
|
|
872
|
+
```v
|
|
873
|
+
account Escrow {
|
|
874
|
+
seller: pubkey;
|
|
875
|
+
buyer: pubkey;
|
|
876
|
+
amount: u64;
|
|
877
|
+
status: u8;
|
|
878
|
+
}
|
|
879
|
+
|
|
880
|
+
pub create_escrow(
|
|
881
|
+
escrow: Escrow @mut @init(payer=seller, space=128) @signer,
|
|
882
|
+
seller: account @mut @signer,
|
|
883
|
+
buyer: pubkey,
|
|
884
|
+
amount: u64
|
|
885
|
+
) -> pubkey {
|
|
886
|
+
require(amount > 0);
|
|
887
|
+
escrow.seller = seller.key;
|
|
888
|
+
escrow.buyer = buyer;
|
|
889
|
+
escrow.amount = amount;
|
|
890
|
+
escrow.status = 0;
|
|
891
|
+
return escrow.key;
|
|
892
|
+
}
|
|
893
|
+
|
|
894
|
+
pub fund_escrow(
|
|
895
|
+
escrow: Escrow @mut,
|
|
896
|
+
buyer: account @signer,
|
|
897
|
+
amount: u64
|
|
898
|
+
) {
|
|
899
|
+
require(escrow.buyer == buyer.key);
|
|
900
|
+
require(escrow.status == 0);
|
|
901
|
+
require(amount == escrow.amount);
|
|
902
|
+
escrow.status = 1;
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
pub release(
|
|
906
|
+
escrow: Escrow @mut,
|
|
907
|
+
buyer: account @signer
|
|
908
|
+
) {
|
|
909
|
+
require(escrow.buyer == buyer.key);
|
|
910
|
+
require(escrow.status == 1);
|
|
911
|
+
escrow.status = 2;
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
pub cancel(
|
|
915
|
+
escrow: Escrow @mut,
|
|
916
|
+
seller: account @signer
|
|
917
|
+
) {
|
|
918
|
+
require(escrow.seller == seller.key);
|
|
919
|
+
require(escrow.status == 0);
|
|
920
|
+
escrow.status = 3;
|
|
921
|
+
}
|
|
922
|
+
```
|
|
923
|
+
|
|
924
|
+
**Patterns exercised:** integer status for state machine, dual-party authorization, lifecycle transitions, exact-amount matching.
|