@5ive-tech/cli 1.0.16 → 1.0.17
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/assets/vm/five_vm_wasm_bg.wasm +0 -0
- package/package.json +1 -1
- package/templates/AGENTS.md +191 -24
|
Binary file
|
package/package.json
CHANGED
package/templates/AGENTS.md
CHANGED
|
@@ -210,27 +210,69 @@ Parser handles:
|
|
|
210
210
|
- list: `::{a, b}`
|
|
211
211
|
- typed list entries: `method foo`, `interface Bar`
|
|
212
212
|
|
|
213
|
-
### 4.9 Interfaces and CPI
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
-
|
|
221
|
-
- `@serializer(
|
|
222
|
-
|
|
223
|
-
-
|
|
224
|
-
|
|
225
|
-
- `@discriminator(
|
|
226
|
-
|
|
227
|
-
- `
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
213
|
+
### 4.9 Interfaces and CPI (Cross-Program Invocation)
|
|
214
|
+
|
|
215
|
+
Interfaces define external program calls. **Empirically verified rules:**
|
|
216
|
+
|
|
217
|
+
1. **Program binding:** always use `@program("...")` (the `@` prefix is required)
|
|
218
|
+
2. **Serializer options:**
|
|
219
|
+
- **Default (bincode):** omit `@serializer(...)` — bincode is the default, works for SPL programs and most Solana programs
|
|
220
|
+
- **Anchor programs (borsh):** use `@anchor` marker — automatically sets borsh serializer **and** auto-generates discriminators from method names
|
|
221
|
+
- **Explicit borsh:** use `@serializer("borsh")` if needed without `@anchor`
|
|
222
|
+
3. **Discriminators:**
|
|
223
|
+
- **Manual:** use single `u8` value inline on method: `method @discriminator(N) (...)`
|
|
224
|
+
- **Anchor auto-generation:** `@anchor` interface automatically computes discriminators from method names — **do not** manually specify `@discriminator` with `@anchor`
|
|
225
|
+
- **Format:** single u8 value, **not** array format `@discriminator([3, 0, 0, 0])`
|
|
226
|
+
4. **Account parameters in interfaces:** use `Account` type, **not** `pubkey`
|
|
227
|
+
- `pubkey` is for data values only; `Account` represents an on-chain account passed to the CPI
|
|
228
|
+
5. **Calling interface methods:** use dot notation `InterfaceName.method(...)`, **not** `InterfaceName::method(...)`
|
|
229
|
+
6. **Passing accounts to CPI:** pass `account`-typed parameters directly, **not** `param.key`
|
|
230
|
+
7. **Function parameters for CPI accounts:** must be typed `account @mut` (not `pubkey`)
|
|
231
|
+
|
|
232
|
+
```v
|
|
233
|
+
// ✅ CORRECT: SPL Token (bincode, manual discriminators)
|
|
234
|
+
interface SPLToken @program("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA") {
|
|
235
|
+
transfer @discriminator(3) (
|
|
236
|
+
source: Account,
|
|
237
|
+
destination: Account,
|
|
238
|
+
authority: Account,
|
|
239
|
+
amount: u64
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// ✅ CORRECT: Anchor program (borsh, auto discriminators)
|
|
244
|
+
interface MyAnchorProgram @anchor @program("...") {
|
|
245
|
+
initialize( // discriminator auto-generated from "initialize"
|
|
246
|
+
state: Account,
|
|
247
|
+
authority: Account,
|
|
248
|
+
value: u64
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// ✅ CORRECT: CPI call
|
|
253
|
+
pub call_external(
|
|
254
|
+
external_account: account @mut,
|
|
255
|
+
authority: account @signer,
|
|
256
|
+
value: u64
|
|
257
|
+
) {
|
|
258
|
+
MyAnchorProgram.initialize(external_account, authority, value);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ❌ WRONG — common mistakes
|
|
262
|
+
// interface Program program("...") ← missing @ on program
|
|
263
|
+
// @discriminator([3, 0, 0, 0]) ← array format, not u8
|
|
264
|
+
// transfer(src: pubkey, dst: pubkey, ...) ← pubkey instead of Account
|
|
265
|
+
// Program::method(...) ← :: instead of .
|
|
266
|
+
// Program.method(account.key, ...) ← .key unnecessary for accounts
|
|
267
|
+
// @anchor with @discriminator(3) ← @anchor auto-generates, don't specify manually
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
CPI hard rules for agents:
|
|
271
|
+
1. Always use `@program("...")` with correct program ID
|
|
272
|
+
2. For Anchor programs: use `@anchor`, omit `@discriminator`
|
|
273
|
+
3. For non-Anchor programs: set `@discriminator(N)` as single u8 on each method, omit `@serializer`
|
|
274
|
+
4. Use `Account` for on-chain account params, scalar types for data params
|
|
275
|
+
5. Call with dot notation and pass account params directly
|
|
234
276
|
|
|
235
277
|
### 4.10 Events and error/enums
|
|
236
278
|
Parser/AST include:
|
|
@@ -635,6 +677,49 @@ pub borrow(
|
|
|
635
677
|
|
|
636
678
|
**Key ingredients:** `let` for intermediate computation, integer math for ratio checks, compound conditions.
|
|
637
679
|
|
|
680
|
+
### 10.8 External Program Integration (CPI)
|
|
681
|
+
|
|
682
|
+
Core pattern: call external Solana programs from within your contract via interfaces.
|
|
683
|
+
|
|
684
|
+
```v
|
|
685
|
+
// Non-Anchor program (bincode, manual discriminators)
|
|
686
|
+
interface ExternalProgram @program("ExternalProgramID111111111111111111111111111") {
|
|
687
|
+
process @discriminator(1) (
|
|
688
|
+
state: Account,
|
|
689
|
+
authority: Account,
|
|
690
|
+
amount: u64
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
// Anchor program (borsh, auto discriminators)
|
|
695
|
+
interface AnchorProgram @anchor @program("AnchorProgramID11111111111111111111111111111") {
|
|
696
|
+
execute( // discriminator auto-generated
|
|
697
|
+
config: Account,
|
|
698
|
+
user: Account,
|
|
699
|
+
value: u64
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
pub perform_action(
|
|
704
|
+
local_state: MyState @mut,
|
|
705
|
+
external_account: account @mut,
|
|
706
|
+
user: account @signer,
|
|
707
|
+
amount: u64
|
|
708
|
+
) {
|
|
709
|
+
require(local_state.authority == user.key);
|
|
710
|
+
require(amount > 0);
|
|
711
|
+
|
|
712
|
+
// CPI to external program
|
|
713
|
+
ExternalProgram.process(external_account, user, amount);
|
|
714
|
+
|
|
715
|
+
// Update local state after CPI
|
|
716
|
+
local_state.last_amount = amount;
|
|
717
|
+
local_state.call_count = local_state.call_count + 1;
|
|
718
|
+
}
|
|
719
|
+
```
|
|
720
|
+
|
|
721
|
+
**Key ingredients:** interface with `@program`, `@discriminator` (or `@anchor` for auto), `Account` types for CPI params, dot-notation calls, `account @mut` function params for all CPI accounts, mixing CPI calls with local state updates.
|
|
722
|
+
|
|
638
723
|
## 11) Mainnet Safety Policy
|
|
639
724
|
|
|
640
725
|
Required preflight gates:
|
|
@@ -699,19 +784,26 @@ Follow this procedure to produce correct 5IVE contracts on first compilation, re
|
|
|
699
784
|
- Set every field to a known value (don't leave uninitialized fields).
|
|
700
785
|
- Return `-> pubkey` with `return account.key;` when callers need the address.
|
|
701
786
|
|
|
702
|
-
### Step 3: Define
|
|
787
|
+
### Step 3: Define interfaces (if calling external programs)
|
|
788
|
+
- Declare `interface Name @program("...") { ... }` at the top of your file.
|
|
789
|
+
- Each method gets `@discriminator(N)` as a single u8 inline: `method @discriminator(N) (...)`.
|
|
790
|
+
- Use `Account` type for on-chain account params, scalar types for data params.
|
|
791
|
+
- **Do not** add `@serializer(...)` — bincode is the default.
|
|
792
|
+
|
|
793
|
+
### Step 4: Define action functions
|
|
703
794
|
- Every state-mutating function takes the relevant account(s) as `AccountType @mut`.
|
|
704
795
|
- Authorization: take an `account @signer` parameter, then `require(state.authority == signer.key);`.
|
|
705
796
|
- Guards: use `require()` with any comparison operator (`==`, `!=`, `<`, `<=`, `>`, `>=`, `!`).
|
|
706
797
|
- For balance operations: always check `require(source.balance >= amount);` before subtraction.
|
|
707
798
|
- For state machines: check `require(state.status == EXPECTED_STATUS);` before transition.
|
|
708
799
|
- Use `let` for intermediate computations (type inference handles it).
|
|
800
|
+
- For CPI calls: pass `account`-typed params directly (not `.key`), use dot notation `Interface.method(...)`.
|
|
709
801
|
|
|
710
|
-
### Step
|
|
802
|
+
### Step 5: Define read/query functions
|
|
711
803
|
- Use `-> ReturnType` syntax for functions that return values.
|
|
712
804
|
- `return state.field;` to return account data.
|
|
713
805
|
|
|
714
|
-
### Step
|
|
806
|
+
### Step 6: Compile and verify
|
|
715
807
|
- Run `5ive build` or `5ive compile src/main.v -o build/main.five`.
|
|
716
808
|
- Fix any parser errors (most common: missing `;` in account fields).
|
|
717
809
|
|
|
@@ -732,6 +824,10 @@ Follow this procedure to produce correct 5IVE contracts on first compilation, re
|
|
|
732
824
|
| Return value | `pub fn(...) -> u64 { return state.value; }` |
|
|
733
825
|
| Fixed string field | `name: string<32>;` |
|
|
734
826
|
| Zero-init pubkey | `state.delegate = 0;` or `state.delegate = pubkey(0);` |
|
|
827
|
+
| Interface decl | `interface Name @program("...") { ... }` |
|
|
828
|
+
| Interface method | `method @discriminator(N) (param: Account, val: u64);` |
|
|
829
|
+
| CPI call | `InterfaceName.method(acct_param, value);` |
|
|
830
|
+
| CPI account param | `name: account @mut` (not `pubkey`) |
|
|
735
831
|
|
|
736
832
|
## 16) Reference Implementations
|
|
737
833
|
|
|
@@ -922,3 +1018,74 @@ pub cancel(
|
|
|
922
1018
|
```
|
|
923
1019
|
|
|
924
1020
|
**Patterns exercised:** integer status for state machine, dual-party authorization, lifecycle transitions, exact-amount matching.
|
|
1021
|
+
|
|
1022
|
+
### 16.4 CPI to External Program (Interface + Cross-Program Calls)
|
|
1023
|
+
|
|
1024
|
+
```v
|
|
1025
|
+
// Interface for external program (non-Anchor, bincode)
|
|
1026
|
+
interface ExternalProgram @program("ExternalProgramID111111111111111111111111111") {
|
|
1027
|
+
update_value @discriminator(5) (
|
|
1028
|
+
state: Account,
|
|
1029
|
+
authority: Account,
|
|
1030
|
+
new_value: u64
|
|
1031
|
+
);
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
// Interface for Anchor program (borsh, auto discriminators)
|
|
1035
|
+
interface AnchorProgram @anchor @program("AnchorProgramID11111111111111111111111111111") {
|
|
1036
|
+
process( // discriminator auto-generated from method name
|
|
1037
|
+
config: Account,
|
|
1038
|
+
user: Account,
|
|
1039
|
+
amount: u64
|
|
1040
|
+
);
|
|
1041
|
+
}
|
|
1042
|
+
|
|
1043
|
+
account Controller {
|
|
1044
|
+
authority: pubkey;
|
|
1045
|
+
counter: u64;
|
|
1046
|
+
last_value: u64;
|
|
1047
|
+
}
|
|
1048
|
+
|
|
1049
|
+
pub init_controller(
|
|
1050
|
+
controller: Controller @mut @init(payer=creator, space=128) @signer,
|
|
1051
|
+
creator: account @mut @signer
|
|
1052
|
+
) -> pubkey {
|
|
1053
|
+
controller.authority = creator.key;
|
|
1054
|
+
controller.counter = 0;
|
|
1055
|
+
controller.last_value = 0;
|
|
1056
|
+
return controller.key;
|
|
1057
|
+
}
|
|
1058
|
+
|
|
1059
|
+
pub call_external(
|
|
1060
|
+
controller: Controller @mut,
|
|
1061
|
+
external_state: account @mut,
|
|
1062
|
+
authority: account @signer,
|
|
1063
|
+
value: u64
|
|
1064
|
+
) {
|
|
1065
|
+
require(controller.authority == authority.key);
|
|
1066
|
+
require(value > 0);
|
|
1067
|
+
|
|
1068
|
+
// CPI to external program
|
|
1069
|
+
ExternalProgram.update_value(external_state, authority, value);
|
|
1070
|
+
|
|
1071
|
+
// Update local state
|
|
1072
|
+
controller.counter = controller.counter + 1;
|
|
1073
|
+
controller.last_value = value;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
pub call_anchor(
|
|
1077
|
+
controller: Controller @mut,
|
|
1078
|
+
anchor_config: account @mut,
|
|
1079
|
+
user: account @signer,
|
|
1080
|
+
amount: u64
|
|
1081
|
+
) {
|
|
1082
|
+
require(controller.authority == user.key);
|
|
1083
|
+
|
|
1084
|
+
// CPI to Anchor program
|
|
1085
|
+
AnchorProgram.process(anchor_config, user, amount);
|
|
1086
|
+
|
|
1087
|
+
controller.counter = controller.counter + 1;
|
|
1088
|
+
}
|
|
1089
|
+
```
|
|
1090
|
+
|
|
1091
|
+
**Patterns exercised:** dual interface types (bincode with manual discriminators, Anchor with auto discriminators), `@program` + `@discriminator` vs `@anchor`, `Account` types in interfaces, dot-notation CPI calls, `account @mut` params for CPI, local state updates after CPI.
|