Neo DevPack for Solidity v0.26.0 — neo-test Dev Environment & Deep Correctness
neo-devpack-solidity v0.26.0 — neo-test Dev Environment & Deep Correctness
Release date: 2026-07-01
Compiler / CLI / workspace: v0.26.0
devpack (@neo-devpack-solidity/contracts): v0.26.0
Target Neo N3 node: v3.10.0 (Gorgon-prep; no hardfork activation)
Canonical change list:
CHANGELOG.md[v0.26.0].
Previous releases: see the
GitHub releases page
andCHANGELOG.mdhistory (previous: v0.25.0).
TL;DR
neo-test— a native, Foundry-style Solidity test runner that
executestest*/testFail*/setUp()directly on the in-tree
NeoVM, with per-test state isolation, cross-contractnew, decoded
revert/Panicreasons,console.logand gas reporting. Bundles
neo-std/{Test,console,Vm}.sol, wired intoneo-forge test. See
docs/TESTING.md.- Foundry cheatcodes —
vm.prank/startPrank/stopPrank/
warp/roll/deal/label/assumeandvm.expectRevert()
(via the HEVM address; no compiler change). - A large correctness wave, dogfooded through
neo-testand
cargo-fuzz/proptest: arithmetic wrap/overflow,bytesNbyte-order at
every binding site, storage aliasing & deep-copy, low-level.call
returndata, ABI encode/decode fidelity, event/inheritance merge, and
try/catchsemantics — 1952 tests across 54 targets, 0 failures.
🧪 The headline: neo-test
Neo now has a first-class, Foundry-shaped testing story that runs on the
same NeoVM the compiler targets — no external node required for the inner
loop:
- Write tests in Solidity:
function testTransfer() public { ... },
testFail*for expected-revert,setUp()for per-test fixtures. - Per-test state isolation and cross-contract
newso multi-
contract flows (Vault/deposit, factory patterns) work out of the box. - Decoded failures —
revert("msg"),require, custom errors and
Panic(0xNN)come back as human-readable reasons, not raw bytes. console.log/console.logBytes, gas accounting, and
value-rich assertions (assertEq failed: 3 != 5).- Cheatcodes through the standard HEVM address:
vm.prank,
startPrank/stopPrank,warp,roll,deal,label,assume,
andvm.expectRevert().
neo-forge test now delegates to neo-test. The bundled neo-std
(Test.sol, console.sol, Vm.sol) ships in-tree via include_str!.
🔧 Correctness fixes (highlights)
Grouped; full list in CHANGELOG.md [v0.26.0]. Many
were found by dogfooding neo-test and by the fuzz harness, then
verified against a real neoxp node.
- Arithmetic — unchecked
-type(intN).min/0 - minnow WRAP
two's-complement (previously produced the out-of-range+2^(N-1),
which also faulted NeoVM's 256-bit integer);addmod(a,b,0)/
mulmod(a,b,0)Panic(0x12);addmodfull-width carry;int256/
uint256 **via soft-arith magnitude (catchable Panic / wrap, no
33-byte fault);mapping(K => uintN)value width. bytesN/ byte semantics — integer-backedbytesNliterals are
big-endian at every binding site (scalar, struct field, array push,
mapping key, call arg, return,constant, multi-return tuple, indexed
event topic);bytesNbitwise read-back viauint256(...);b[i]is
abytes1;intN(bytesN)endianness;bytesNconstant comparison
(fixed a byte-reversed access-control check).- Storage — storage
structpassed by reference to an internal
function aliases the slot;T[] memory m = storageArrdeep-copies;
storagebyteselement writedata[i] = vpersists;bytes
push/pop. - ABI & low-level calls — internal call to a public array/
bytes/
stringreturner decodes the ABI blob; low-level.callreturndata
is the raw EVM ABI envelope (no Neo serialize framing), a no-reason
revert is empty, and(bool ok, )reportsfalseon revert; strict
abi.decodetype fidelity;abi.encode/encodePackedByteString;
partial tuple destructure from a cross-contract call. - Events / inheritance / merge — a contract keeps its own event
declarations when another references it by type; anew-deployed
contract's public method reaches its own concrete internal helper
(was dropped →PUSH0→ write lost); cross-contractmsg.senderfor
new-deployed callees. try/catch& control flow — boundedTRYnesting (VM-DoS fix) +
uncatchableExecutionEngineLimits;catch Panic/catch Error
matching against real-node faults; balancedTRYframe on every catch
exit; modifier/base-constructor args evaluated exactly once.- Type resolution & devpack — integer-literal overload resolution;
address.balance/.code/.codehashinference; NeoVMEQUAL
type-strictness; devpackmultiSigMintauthorization, stake-reward
settlement, NEP-11 oracle/curation/minter-royalty paths.
Known limitations (tracked for a follow-up)
A handful of deep sim-fidelity / model-level items are documented but not
yet fixed: abi.encodeWithSignature used as raw bytes vs. the Neo
method-name .call optimization; abi.encode of fixed-size arrays
(uintN[K]) using dynamic layout; nested struct-array-member storage
keys; inherited-getter dispatch and inherited base-constructor state when
a contract is instantiated via new in the in-tree simulator.
📊 Headline numbers
| Metric | v0.25.0 | v0.26.0 |
|---|---|---|
| Native Solidity test runner | — | neo-test |
| Foundry cheatcodes | — | 9 (prank/warp/roll/deal/label/assume/expectRevert/…) |
| Test suites green | 47 | 54 |
| Total tests | 1,488 | 1,952 |
| Test failures | 0 | 0 |
| Backlog compiler bugs fixed this cycle | — | 30+ |
🚀 How to upgrade
Backwards-compatible release — no public-API breaks or renames. Cargo and
npm users pick up v0.26.0 on their next dependency resolution.
CLI users: rebuild with cargo install --path . --version 0.26.0
or download the prebuilt binary from the
release page.
Library users consuming neo_devpack_solidity from another crate:
pick up 0.26.0 via cargo update.
devpack users: npm install @neo-devpack-solidity/contracts@0.26.0.
Test authors: write Solidity tests and run neo-test <file>.sol
(or neo-forge test). See docs/TESTING.md.
🧪 Verification
cargo test --release✅ 1,952 passed / 54 targets / 0 failed
(integration + lib unit + cargo-fuzz/proptest)cargo fmt --all -- --check✅cargo clippy✅