- Ensure you successfully set up your dev environment.
Writing a smart contract
Overview of smart contract samples.
Prerequisites
Note:
Smart contract samples
| Programming language | |
|---|---|
| Solidity | Note: Since QANplatform is Ethereum and EVM-compatible, you can write smart contracts in the same way as you do on Ethereum or other EVM-compatible blockchains. |
| TypeScript (TS) | Writing a smart contract in TypeScript (TS) |
| C++ | Writing a smart contract in C++ |
| C | Writing a smart contract in C |
| Golang (Go) | Writing a smart contract in Golang (Go) |
| Python | Writing a smart contract in Python |
Why storage slots must be declared upfront
QVM contracts run inside an isolated sandbox environment. Unlike Solidity contracts, which execute natively on the node and can access storage slots dynamically at runtime, QVM contracts cannot reach outside the sandbox to fetch storage values on demand. All storage slots a contract intends to read must be declared before the transaction is submitted, so the execution layer can fetch and inject them as environment variables prior to execution.
How storage slots map to environment variables
Each storage slot name is prefixed with DB_ when exposed inside the contract.
For example:
| Storage Slot Name | Environment Variable inside Contract |
|---|---|
| QVM_INIT_MAXUSER | DB_QVM_INIT_MAXUSER |
| TOTALUSERS | DB_TOTALUSERS |
| USER_CURRENT | DB_USER_CURRENT |
What happens if slots are not declared
If the -r flag is omitted, qvmctl does not create an AccessList for those slots. The execution layer has no knowledge of which slots to fetch, so all storage reads inside the contract return empty values. This is a silent failure - the contract executes without error but operates on empty state.
How to declare read slots using qvmctl
Use the -r flag followed by a comma-separated list of slot names. Example for a contract method diag that reads three slots:
docker run --rm -v "${PWD}:/ws" qanplatform/qvmctl tx -loglevel debug \
-rpc "https://rpc-testnet.qanplatform.com" \
-privkey /ws/privkey.hex \
-r QVM_INIT_MAXUSER,TOTALUSERS,USER_CURRENT \
<address> diag
The -r flag instructs qvmctl to: 1. Build an AccessList transaction that includes the specified storage slots 2. Have the execution layer fetch the current values of those slots from on-chain storage 3. Inject them as environment variables (DB_<SLOT_NAME>) before the contract function runs
Best practice
Review every storage read in your contract source code and ensure all slot names are listed in the -r flag when calling qvmctl tx. Any slot not listed will appear as an empty string inside the contract.