### Install Plank using plankup Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/getting-started.md Use this command to download and install the latest Plank binary and local documentation. ```bash curl -L https://install.plankevm.org | bash ``` -------------------------------- ### Install Plank Compiler Source: https://github.com/plankevm/plank-monorepo/blob/main/README.md Run this command to install the Plank compiler and the plankup tool. ```bash curl -L install.plankevm.org | bash && plankup ``` -------------------------------- ### Install Plank with plankup Source: https://context7.com/plankevm/plank-monorepo/llms.txt Use the plankup installer to get the latest Plank compiler and configure editor syntax highlighting. ```bash # Install plankup and the Plank compiler curl -L https://install.plankevm.org | bash # Update to the latest version plankup # Compile a contract plank build my_contract.plk # Open local documentation in a browser plank doc # Jump to a specific documentation topic plank doc comptime ``` -------------------------------- ### Import As Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Demonstrates importing a module and aliasing it with 'as'. ```plank import very_nice::hey as nice; ``` -------------------------------- ### Import Simple Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Shows a basic import statement for a nested module. ```plank import very_nice::hey::bob; ``` -------------------------------- ### Import Group Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Shows how to import multiple items from a module, with aliasing for some. ```plank import std::math::{add as a, sub,}; ``` -------------------------------- ### Import Glob Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Illustrates importing all items from a module using the glob operator '*'. ```plank import very_nice::hey::haha::*; ``` -------------------------------- ### Open Plank Documentation Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/getting-started.md Open the locally installed Plank documentation in your web browser. ```bash plank doc ``` -------------------------------- ### Return Statement Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Demonstrates a simple function definition with a return statement. ```plank const f = fn () u256 { return 42; }; ``` -------------------------------- ### Zed Install Dev Extension Command Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-zed/README.md Use this command in Zed's Command Palette to install the Plank extension from a local development directory. ```shell zed: install dev extension ``` -------------------------------- ### Binary Operators Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Illustrates the use of various binary operators with different precedence levels. ```plank const x = a or b and c == d | e ^ f & g << h + i * j; ``` -------------------------------- ### Merkle Airdrop Verification in Plank Source: https://context7.com/plankevm/plank-monorepo/llms.txt Verifies Merkle proofs on-chain before marking an address as claimed. This example demonstrates `while` loops over variable-length calldata, `keccak256` node sorting, and storage-backed claim tracking. It requires specific constants for selectors, slots, and topics, and uses `init` for setup and `run` for execution logic. ```Plank import std::storage::map_slot_hash; import std::constructor::return_runtime; const CLAIM_SELECTOR = 0x3d13f874; const MERKLE_ROOT_SLOT = 0; const HAS_CLAIMED_SLOT_BASE = 1; const CLAIMED_TOPIC = 0xd8138f8a3f377c5259ca548e70e4c2de94f129f5a11036a15b69513cba2b426a; init { let args_buf = @malloc_zeroed(32); @evm_codecopy(args_buf, @init_end_offset(), 32); @evm_sstore(MERKLE_ROOT_SLOT, @mload32(args_buf)); return_runtime(); } run { let selector = @evm_calldataload(0) >> 224; if selector == CLAIM_SELECTOR { // Guard: already claimed? let address = @evm_calldataload(4); let claim_slot = map_slot_hash(address, HAS_CLAIMED_SLOT_BASE); if @evm_sload(claim_slot) != 0 { @evm_revert(@malloc_uninit(0), 0); } let amount = @evm_calldataload(36); let offset = 4 + @evm_calldataload(68); let proof_length = @evm_calldataload(offset); // Compute leaf = keccak256(address ++ amount) let buf = @malloc_uninit(64); @mstore32(buf, address); @mstore32(buf +% 32, amount); let mut node = @evm_keccak256(buf +% 12, 52); // Walk proof elements, sorting pairs before hashing let mut i = 0; while i < proof_length { let sibling = @evm_calldataload(offset + 32 + i * 32); if node <= sibling { @mstore32(buf, node); @mstore32(buf +% 32, sibling); } else { @mstore32(buf, sibling); @mstore32(buf +% 32, node); } node = @evm_keccak256(buf, 64); i = i + 1; } // Verify root if node != @evm_sload(MERKLE_ROOT_SLOT) { @evm_revert(@malloc_uninit(0), 0); } // Mark claimed and emit event @evm_sstore(claim_slot, 1); @mstore32(buf, amount); @evm_log2(buf, 32, CLAIMED_TOPIC, address); @evm_return(@malloc_uninit(0), 0); } else { @evm_revert(@malloc_uninit(0), 0); } } ``` -------------------------------- ### SIR Basic Block Example: For Loop Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/sir/docs/README.md Illustrates a simple for-loop structure in SIR, showing how basic blocks and control flow are represented. This example increments a variable 'i' until it reaches 10. ```sir // BB called `for_loop_entry`, no inputs 1 output. for_loop_entry -> start_i { start_i = const 0 // Essentially `i := start_i` => @for_loop } // BB called `for_loop_body`, 1 input 1 output. for_loop_body i -> next_i { c1 = const 1 next_i = add i c1 c10 = const 10 next_i_lt_10 = lt next_i c10 // Jumping back to self is equivalent to `i := next_i`. => next_i_lt_10 ? @for_loop_body : @for_loop_end } // BB for_loop_end end_i { } ``` -------------------------------- ### Install Plank VS Code Extension from Source Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-vscode/README.md Use this command to link the local Plank monorepo to your VS Code extensions directory for development. Restart VS Code or reload the window after installation. ```sh ln -s /path/to/plank-monorepo/plank-vscode ~/.vscode/extensions/plankevm ``` -------------------------------- ### Let Statement Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Shows how to declare immutable and mutable variables using let statements. ```plank init { let x = 1; let mut y: u256 = 2; } ``` -------------------------------- ### Member Access Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Demonstrates accessing nested members of an object or struct. ```plank const x = foo.bar.baz; ``` -------------------------------- ### SIR IR Simple Function Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/sir/docs/ir_text_format.md A basic SIR IR function named 'main' with an 'entry' block that defines constants, loads calldata, performs addition, and returns values. ```sir fn main: entry { c0 = const 0 c32 = const 32 a = calldataload c0 b = calldataload c32 sum = add a b return c0 c32 } ``` -------------------------------- ### Memory Allocation with @malloc_uninit in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/what-makes-plank-different.md Example of using `@malloc_uninit` for memory allocation and `@mstore32` for storing data, followed by `@evm_keccak256` for hashing. This pattern is useful for preparing data buffers for hashing or other EVM operations. ```plank const map_slot_hash = fn (key: u256, base_slot: u256) u256 { let buf = @malloc_uninit(64); @mstore32(buf, key); @mstore32(buf +% 32, base_slot); @evm_keccak256(buf, 64) }; ``` -------------------------------- ### SIR IR Function with Multiple Blocks and I/O Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/sir/docs/ir_text_format.md An example of a SIR IR function with multiple blocks ('entry' and 'ret') that handle input parameters and produce output values for sum and difference. ```sir fn main: entry lhs rhs -> sum_out diff_out { sum_out = add lhs rhs diff_out = sub lhs rhs => @ret } ret sum_in diff_in -> total { total = add sum_in diff_in iret } ``` -------------------------------- ### Update Plank using plankup Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/getting-started.md Run this command to update your Plank installation to the latest version. ```bash plankup ``` -------------------------------- ### SIR IR Switch Statement Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/sir/docs/ir_text_format.md Demonstrates a switch statement in SIR IR for multi-way branching. The 'entry' block dispatches to different case blocks ('case_zero', 'case_one', 'case_two') or a 'fallback' block based on a selector value. ```sir fn dispatch: entry selector { switch selector { 0 => @case_zero 1 => @case_one 2 => @case_two default => @fallback } } case_zero { // Handle case 0 stop } case_one { // Handle case 1 stop } case_two { // Handle case 2 stop } fallback { // Default handler revert } ``` -------------------------------- ### Emit Solidity-Compatible Panic Codes Source: https://context7.com/plankevm/plank-monorepo/llms.txt Use `std::sol` to emit panics that follow the Solidity ABI convention, allowing Solidity tooling to recognize them. This example shows how to revert with an arithmetic overflow panic. ```plank import std::sol::{SolPanicCode, PANIC_SELECTOR, ARITH_OVERFLOW_UNDERFLOW, DIV_BY_ZERO, OUT_OF_BOUNDS_ACCESS}; import std::core_ops::arith_error; // Revert with a Solidity-compatible arithmetic overflow panic arith_error(ARITH_OVERFLOW_UNDERFLOW); // encodes Panic(0x11) and reverts // Available panic codes: // ASSERT_FALSE 0x01 // ARITH_OVERFLOW_UNDERFLOW 0x11 // DIV_BY_ZERO 0x12 // ENUM_CONVERT_FAIL 0x21 // INVALID_BYTE_ARRAY_ACCESS 0x22 // POP_EMPTY 0x31 // OUT_OF_BOUNDS_ACCESS 0x32 // OVER_ALLOC 0x41 ``` -------------------------------- ### Plank EVM Opcode Builtins: Events (log0-log4) Source: https://context7.com/plankevm/plank-monorepo/llms.txt Emit events using `log` opcodes, specifying data buffers and topics. `log3` is shown as an example. ```plank // Events (log0–log4) @evm_log3(data_buf, 32, TRANSFER_TOPIC, from, to); ``` -------------------------------- ### Proxy Deployment Entry Points Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/examples/minimal-proxy.md Exposes two public entry points for deploying proxies: `clone` for non-deterministic deployment using `create`, and `clone_deterministic` for deterministic deployment using `create2` with a salt loaded from calldata. ```plank const clone = fn () never { deploy_clone(void, {}); }; const clone_deterministic = fn () never { let salt = @evm_calldataload(36); deploy_clone(u256, salt); }; ``` -------------------------------- ### Plank Initialization and Run Blocks Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/docs/Grammar.md Defines syntax for 'init' and 'run' blocks, which likely handle program initialization and execution entry points. ```ebnf init = "init" block run = "run" block ``` -------------------------------- ### Struct Definition Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Defines a struct with fields without explicit type indices. ```plank const Values = struct { x: u256, b: u256 }; ``` -------------------------------- ### Jump to Specific Documentation Topic Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/getting-started.md Open the Plank documentation directly to a specific topic, such as 'comptime'. ```bash plank doc comptime ``` -------------------------------- ### Deploy Runtime Bytecode with `return_runtime` Source: https://context7.com/plankevm/plank-monorepo/llms.txt Ensures the contract's `run` bytecode is copied from initcode and returned via `RETURN`. This must be the last call in the `init` section. ```plank import std::constructor::return_runtime; init { // ... initialization logic (set storage, emit events) ... return_runtime(); // must be the last call in init; never returns } // Internally equivalent to: // let buf = @malloc_uninit(@runtime_length()); // @evm_codecopy(buf, @runtime_start_offset(), @runtime_length()); // @evm_return(buf, @runtime_length()); ``` -------------------------------- ### Run All Tests Including SIR Solidity Diff Tests Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/AGENTS.md Run all tests, including those that perform Solidity diff tests against the SIR, using the 'just test-all' command. ```bash just test-all ``` -------------------------------- ### Leaf Computation in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/examples/merkle-airdrop.md Demonstrates packing an address and amount into a buffer for leaf computation using `malloc_uninit`, `mstore32`, and `evm_keccak256`. ```plank let buf = @malloc_uninit(64); @mstore32(buf, address); @mstore32(buf +% 32, amount); let mut node = @evm_keccak256(buf +% 12, 52); ``` -------------------------------- ### Comptime Generic Clone Deployment Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/examples/minimal-proxy.md A generic helper function for deploying clones using either `create` (for non-deterministic addresses) or `create2` (for deterministic addresses). It uses comptime generics to specialize the deployment logic based on the salt type (`void` or `u256`), avoiding runtime branching. ```plank const deploy_clone = fn (comptime SaltT: type, salt: SaltT) never { let address = if SaltT == void { @evm_create(0, buf, 55) } else if SaltT == u256 { @evm_create2(0, buf, 55, salt) } else { // compile-time error. let _unsupported_clone_type_error: u256 = true; }; }; ``` -------------------------------- ### Importing Modules in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/what-makes-plank-different.md Demonstrates how to import functionality from standard library modules in Plank. Use explicit imports for code organization and to access utilities like ABI encoding and math functions. ```plank import std::abi::{abi_encode, abi_decode}; import std::math::max; ``` -------------------------------- ### Plank Contract Structure: init and run Source: https://context7.com/plankevm/plank-monorepo/llms.txt Define contract deployment logic in `init` and runtime logic in `run`. Ensure `return_runtime()` is called in `init` to deploy the runtime bytecode. ```plank import std::constructor::return_runtime; const MAGIC_NUMBER_SLOT = 0; const GET_SELECTOR = 0x6d4ce63c; init { // Read 32-byte constructor argument and store it let buf = @malloc_zeroed(32); @evm_codecopy(buf, @init_end_offset(), 32); @evm_sstore(MAGIC_NUMBER_SLOT, @mload32(buf)); return_runtime(); // deploy the run block as runtime bytecode } run { let selector = @evm_calldataload(0) >> 224; if selector == GET_SELECTOR { let buf = @malloc_uninit(32); @mstore32(buf, @evm_sload(MAGIC_NUMBER_SLOT)); @evm_return(buf, 32); } else { @evm_revert(@malloc_uninit(0), 0); } } ``` -------------------------------- ### Run All Rust Tests Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/AGENTS.md Execute all Rust tests within the project using the 'just test' command. ```bash just test ``` -------------------------------- ### SIR IR Conditional Branch Example Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/sir/docs/ir_text_format.md Illustrates a conditional branch in SIR IR. The 'entry' block branches to 'true_case' or 'false_case' based on a condition, with both cases storing a value and then proceeding to a 'done' block. ```sir fn conditional: entry condition value_a value_b { => condition ? @true_case : @false_case } true_case result_in { mstore256 result_in value_a => @done } false_case result_in { mstore256 result_in value_b => @done } done { stop } ``` -------------------------------- ### Basic Declarations and Structs in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Demonstrates constant declarations, function definitions, struct definitions, and initialization blocks. Use for basic variable and type definitions. ```plank const my_func = fn () u256 { x = 18446744073709551616; }; const IMPORTANT_NUM: u256 = 3; const ByteBuffer = struct 64 { ptr: byteptr, len: u256, }; init { x = 3; y = 24; } run { } ``` -------------------------------- ### SIR IR Data Segments Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/sir/docs/ir_text_format.md Example of defining and accessing data segments in SIR IR. 'data' directives define byte sequences, and 'data_offset' is used to retrieve the memory offset of a named data segment. ```sir data greeting 0x48656c6c6f2c20576f726c6421 data config 0xdeadbeef fn main: entry { offset = data_offset .greeting // Use data offset stop } ``` -------------------------------- ### Deploy ERC1167 Proxies with Plank EVM Source: https://context7.com/plankevm/plank-monorepo/llms.txt Use this snippet to deploy ERC1167 proxies. It supports both `create` (void salt) and `create2` (u256 salt) methods. Ensure correct calldata is provided for the implementation address. ```plank import std::constructor::return_runtime; const CLONE_SELECTOR = 0x8124b78e; const CLONE_DETERMINISTIC_SELECTOR = 0xb86b2ceb; const CLONE_CREATED_TOPIC = 0xbe2f3d28fdeb5839123d65fd47ec2f5915c715d2b527b9e229123706fdecfc85; init { return_runtime(); } run { let selector = @evm_calldataload(0) >> 224; if selector == CLONE_SELECTOR { deploy_clone(void, {}); } else if selector == CLONE_DETERMINISTIC_SELECTOR { deploy_clone(u256, @evm_calldataload(36)); } else { @evm_revert(@malloc_uninit(0), 0); } } // Comptime generic: SaltT is void (create) or u256 (create2) // The compiler emits two fully specialized, branch-free versions. const deploy_clone = fn (comptime SaltT: type, salt: SaltT) never { let address = @evm_calldataload(4); let len = 32 + 20 + 15; // 55-byte ERC1167 proxy let buf = @malloc_uninit(len); // Write backwards for efficient 32-byte store alignment @mstore32(buf +% (len - 32), 0x5af43d82803e903d91602b57fd5bf3); // suffix @mstore32(buf +% (len - 32 - 15), address); // impl addr @mstore32(buf +% (len - 32 - 15 - 20), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73); // prefix let deployed = if SaltT == void { @evm_create(0, buf +% (32 - 20), 55) } else if SaltT == u256 { @evm_create2(0, buf +% (32 - 20), 55, salt) } else { let _unsupported_clone_type_error: u256 = true; // compile-time type error }; @mstore32(buf, deployed); @evm_log1(buf, 32, CLONE_CREATED_TOPIC); @evm_return(buf, 32); }; ``` -------------------------------- ### Plank Arithmetic and Bitwise Operators Source: https://context7.com/plankevm/plank-monorepo/llms.txt Demonstrates standard and wrapping arithmetic operators, explicit rounding division, and bitwise operations. Arithmetic operators revert on overflow/underflow by default; use the `%` suffix for wrapping behavior. ```plank let sum = a + b; // reverts on overflow let diff = a - b; // reverts on underflow let prod = a * b; // reverts on overflow let slot = base +% offset; // wraps (modular) let dec = x -% 1; // wraps 7 -/ 2 // == 3 (floor division) 7 +/ 2 // == 4 (ceiling division) // Bitwise let masked = value & 0xff; let shifted = value >> 224; ``` ```plank // Logical if a > 0 and b > 0 { /* both */ } if a == 0 or b == 0 { /* either */ } ``` -------------------------------- ### Plank Let Binding Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/docs/Grammar.md Defines how to declare and initialize local variables in Plank, with optional mutability and type annotations. ```ebnf let = "let" "mut"? IDENT (":" expr)? "=" expr ``` -------------------------------- ### While Loop in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Demonstrates a standard while loop within an init block. Use for iterative operations that depend on a condition. ```plank init { while x { y = 1; } } ``` -------------------------------- ### Run Formatter and Linter Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/AGENTS.md Execute the 'just check' command to run the code formatter and linter (clippy) to maintain code quality. ```bash just check ``` -------------------------------- ### Math Utilities with std::math Source: https://context7.com/plankevm/plank-monorepo/llms.txt Provides basic arithmetic helpers for common EVM patterns, including `max`, `min`, and `ceil32`. `ceil32` is particularly useful for rounding up to the nearest 32-byte boundary, often required for ABI encoding offsets. ```plank import std::math::{max, min, ceil32}; let bigger = max(a, b); let smaller = min(a, b); // Round up to the nearest 32-byte boundary (used for ABI encoding offsets) let padded = ceil32(n); // e.g. ceil32(33) == 64, ceil32(32) == 32 ``` -------------------------------- ### Plank EVM Opcode Builtins: Contract Creation Source: https://context7.com/plankevm/plank-monorepo/llms.txt Use built-in functions to create new contracts, with `create2` offering deterministic address generation using a salt. ```plank // Contract creation let addr = @evm_create(value, code_ptr, code_len); let addr2 = @evm_create2(value, code_ptr, code_len, salt); ``` -------------------------------- ### Direct EVM Opcode Access in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/what-makes-plank-different.md Demonstrates direct calls to EVM opcodes for common operations like loading data, storing values, and retrieving caller information. Use this when you need fine-grained control over EVM state and data. ```plank let caller = @evm_caller(); let amount = @evm_calldataload(4); let slot = map_slot_hash(caller, BALANCE_SLOT); @evm_sstore(slot, amount); ``` -------------------------------- ### Build ERC1167 Proxy Bytecode in Memory Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/examples/minimal-proxy.md Constructs the 55-byte ERC1167 minimal proxy bytecode directly in memory. It assembles the bytecode by writing the implementation address, a fixed prefix, and a fixed suffix in reverse order for efficiency. ```plank let len = 32 + 20 + 15; let buf = @malloc_uninit(len); @mstore32(buf +% (len - 32), 0x5af43d82803e903d91602b57fd5bf3); @mstore32(buf +% (len - 32 - 15), address); @mstore32(buf +% (len - 32 - 15 - 20), 0x3d602d80600a3d3981f3363d3d373d3d3d363d73); ``` -------------------------------- ### Compile Plank Contract Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/getting-started.md Compile your Plank contract file into an executable artifact. ```bash plank build magic_number.plk ``` -------------------------------- ### Full ERC20 Token Implementation in Plank Source: https://context7.com/plankevm/plank-monorepo/llms.txt A complete ERC20 token contract demonstrating Plank's `init`/`run` structure, opcode builtins, storage manipulation, ABI encoding, and event emission. Handles balance, transfer, and approval logic. ```plank import std::abi::abi_encode; import std::membytes::{membytes, membytes_from_ptr}; import std::storage::map_slot_hash; import std::constructor::return_runtime; const TOTAL_SUPPLY = 1000000; const TOTAL_SUPPLY_SLOT = 0; const BALANCE_SLOT_BASE = 1; const ALLOWANCE_SLOT_BASE = 2; const BALANCE_OF_SELECTOR = 0x70a08231; const TRANSFER_SELECTOR = 0xa9059cbb; const APPROVE_SELECTOR = 0x095ea7b3; const TRANSFER_FROM_SELECTOR = 0x23b872dd; const TRANSFER_TOPIC = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; const APPROVAL_TOPIC = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; init { @evm_sstore(TOTAL_SUPPLY_SLOT, TOTAL_SUPPLY); let caller = @evm_caller(); @evm_sstore(map_slot_hash(caller, BALANCE_SLOT_BASE), TOTAL_SUPPLY); let buf = @malloc_uninit(32); @mstore32(buf, TOTAL_SUPPLY); @evm_log3(buf, 32, TRANSFER_TOPIC, 0, caller); // emit Transfer(address(0), caller, supply) return_runtime(); } run { let selector = @evm_calldataload(0) >> 224; if selector == BALANCE_OF_SELECTOR { let slot = map_slot_hash(@evm_calldataload(4), BALANCE_SLOT_BASE); let buf = @malloc_uninit(32); @mstore32(buf, @evm_sload(slot)); @evm_return(buf, 32); } else if selector == TRANSFER_SELECTOR { let to = @evm_calldataload(4); let amount = @evm_calldataload(36); let from = @evm_caller(); let from_slot = map_slot_hash(from, BALANCE_SLOT_BASE); let bal_from = @evm_sload(from_slot); if bal_from < amount { @evm_revert(@malloc_uninit(0), 0); } @evm_sstore(from_slot, bal_from - amount); let to_slot = map_slot_hash(to, BALANCE_SLOT_BASE); @evm_sstore(to_slot, @evm_sload(to_slot) + amount); let buf = @malloc_uninit(32); @mstore32(buf, amount); @evm_log3(buf, 32, TRANSFER_TOPIC, from, to); @mstore32(buf, 1); @evm_return(buf, 32); } else if selector == APPROVE_SELECTOR { let spender = @evm_calldataload(4); let amount = @evm_calldataload(36); let caller = @evm_caller(); let slot = map_slot_hash(spender, map_slot_hash(caller, ALLOWANCE_SLOT_BASE)); @evm_sstore(slot, amount); let buf = @malloc_uninit(32); @mstore32(buf, amount); @evm_log3(buf, 32, APPROVAL_TOPIC, caller, spender); @mstore32(buf, 1); @evm_return(buf, 32); } else { @evm_revert(@malloc_uninit(0), 0); } } ``` -------------------------------- ### Plank Zed Extension Project Layout Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-zed/README.md Overview of the directory structure for the Plank Zed extension, including configuration and grammar files. ```plaintext plank-zed/ extension.toml # Zed extension manifest (registers the grammar) languages/plank/ config.toml # Language metadata (name, suffixes, comments) highlights.scm # Tree-sitter syntax highlighting queries brackets.scm # Bracket-matching queries indents.scm # Auto-indentation queries ``` -------------------------------- ### Comptime ABI Encoding in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/what-makes-plank-different.md Shows how to use `comptime` and the standard library's `abi_encode` function to automatically encode a struct into ABI format. Define your struct, pass it along with the data to `abi_encode`, and then return the encoded data. ```plank import std::abi::abi_encode; const Transfer = struct { to: u256, amount: u256 }; let encoded = abi_encode(Transfer, transfer); @evm_return(encoded.ptr, encoded.len); ``` -------------------------------- ### Plank Import Syntax Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/docs/Grammar.md Details the various ways to import modules and identifiers in Plank, including aliasing and group imports. ```ebnf import = "import" IDENT ("::" IDENT)* (suffix_import_all | suffix_import_as | suffix_import_group)? ";" suffix_import_all = "::" "*" suffix_import_as = "as" IDENT suffix_import_group = "::" "{" import_group_item ("," import_group_item)* ","? "}" import_group_item = IDENT ("as" IDENT)? ``` -------------------------------- ### Parse SIR IR Text to Program Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/sir/docs/ir_text_format.md Demonstrates basic usage of the `sir_parser::parse` function to convert SIR IR text into an in-memory `sir_data::Program`. Handles both successful parsing and potential errors. ```rust use sir_parser::parse; // Parse IR text into an in-memory IR program let source = r#"\nfn main:\n entry {\n c0 = const 0\n c32 = const 32\n a = calldataload c0\n b = calldataload c32\n sum = add a b\n return c0 c32\n }\n"#; match parse(source) { Ok(program) => { // program is sir_data::Program println!("Parsed {} functions", program.functions().len()); } Err(errors) => { // Handle parse errors for error in errors { eprintln!("Parse error: {:?}", error); } } } ``` -------------------------------- ### ABI Encoding in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/examples/erc20.md Shows how to encode raw data into ABI format using `abi_encode`. This involves allocating memory, storing data, wrapping it with `membytes`, and returning the encoded result. ```plank let ptr = @malloc_uninit(10); @mstore10(ptr, 0x506c616e6b546f6b656e); let encoded = abi_encode(membytes, membytes_from_ptr(ptr, 10)); @evm_return(encoded.ptr, encoded.len); ``` -------------------------------- ### Emit Transfer Event in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/examples/erc20.md Demonstrates emitting a Transfer event with three indexed topics and data using `@evm_log3`. Ensure topics and data are correctly allocated and stored in memory. ```plank @evm_log3(buf, 32, TRANSFER_TOPIC, from, to); ``` -------------------------------- ### Source File with Multiple Imports Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Illustrates the tree-sitter grammar for a source file containing several import statements, including one with a suffix import group. ```tree-sitter grammar (source_file (import (identifier) (identifier) (suffix_import_group (import_group_item (identifier)) (import_group_item (identifier)) (import_group_item (identifier)) (import_group_item (identifier)))) (import (identifier) (identifier) (identifier)) (import (identifier) (identifier) (identifier))) ``` -------------------------------- ### Run Tests for a Specific Crate Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/AGENTS.md Use this command to run tests for a particular crate during development to ensure its correctness. ```bash cargo test -p ``` -------------------------------- ### Plank `std::storage` Utilities Source: https://context7.com/plankevm/plank-monorepo/llms.txt Provides functions for deriving EVM storage slots and handling variable-length byte arrays. Use `map_slot_hash` for nested mappings and `sstore_bytes`/`sload_bytes` for dynamic data. ```plank import std::storage::{map_slot_hash, slot_hash, sstore_bytes, sload_bytes}; const BALANCE_SLOT_BASE = 1; const ALLOWANCE_SLOT_BASE = 2; // Derive a mapping slot: keccak256(key ++ base_slot) let balance_slot = map_slot_hash(caller, BALANCE_SLOT_BASE); let balance = @evm_sload(balance_slot); @evm_sstore(balance_slot, balance - amount); // Nested mapping (allowances): keccak256(spender ++ keccak256(owner ++ base)) let allowance_slot = map_slot_hash(spender, map_slot_hash(owner, ALLOWANCE_SLOT_BASE)); // Store variable-length bytes across multiple storage slots import std::membytes::{membytes, membytes_from_ptr}; let ptr = @malloc_uninit(10); @mstore10(ptr, 0x506c616e6b546f6b656e); // "PlankToken" let data = membytes_from_ptr(ptr, 10); sstore_bytes(3, data); // stored at slot 3 // Load it back let loaded = sload_bytes(3); // returns membytes { ptr, len } ``` -------------------------------- ### Function with Comptime Parameters in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Shows a function definition that accepts a comptime type parameter. This allows for generic programming where types are determined at compile time. ```plank const f = fn (comptime T: Type, x: T) T { x }; ``` -------------------------------- ### Merkle Proof Iteration in Calldata Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/examples/merkle-airdrop.md This snippet shows how to iterate over proof elements stored in calldata using a while loop. It demonstrates reading variable-length data for runtime-sized proofs. ```plank let mut i = 0; while i < proof_length { let proof_element = @evm_calldataload(offset + 32 + i * 32); ... i = i + 1; } ``` -------------------------------- ### Inline While Loop in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Shows an inline while loop syntax. This is a more compact way to write simple loops. ```plank init { inline while x { y = 1; } } ``` -------------------------------- ### Comptime Function for Access Control in Plank Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/what-makes-plank-different.md Illustrates defining a `comptime` function in Plank to enforce access control, such as checking if the caller is the owner before executing an action. This pattern replaces Solidity's modifiers with first-class functions. ```plank const require_owner = fn(comptime action: function) void { if @evm_caller() != OWNER { revert_empty(); } action(); }; ``` -------------------------------- ### Run Tests for a Specific Crate Source: https://github.com/plankevm/plank-monorepo/blob/main/plankc/sir/AGENTS.md Use this command to narrow down test execution to a specific crate within the repository, improving feedback loops during development. ```bash cargo test -p ``` -------------------------------- ### Comptime Parameter for Function Specialization Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-doc/src/comptime.md Employ `comptime` parameters to instruct the compiler to specialize a function for each distinct value it's invoked with. This enables zero-cost generics. ```plank const DOUBLE = fn(comptime x: u256) u256 { x * 2 }; ``` -------------------------------- ### Source File with Comments Source: https://github.com/plankevm/plank-monorepo/blob/main/plank-tree-sitter/test/corpus/simple.txt Represents a source file structure that includes a line comment and multiple block comments. ```tree-sitter grammar (source_file (line_comment) (block_comment) (block_comment) (block_comment)) ``` -------------------------------- ### Plank Memory Management: Allocation and Copying Source: https://context7.com/plankevm/plank-monorepo/llms.txt Manage memory using `@malloc_uninit` for uninitialized or `@malloc_zeroed` for zero-initialized blocks. Use `@mstore32` and `@mload32` for 32-byte words, and `@mcopy` for memory region copying. ```plank // Allocate 64 bytes of uninitialized memory let buf = @malloc_uninit(64); // Write two 32-byte words @mstore32(buf, key); @mstore32(buf +% 32, base_slot); // Read back a word let word = @mload32(buf); // Allocate zero-initialized memory (safe for partial writes) let zeroed = @malloc_zeroed(32); // Copy memory regions @mcopy(dst +% offset, src, len); ```