Solidity
Smart contracts for Ethereum.
Solidity is the main language for writing smart contracts: programs that run on Ethereum and compatible blockchains. Contracts hold and move digital assets according to code that anyone can verify. AI agents increasingly interact with blockchains, for example to pay for services or verify actions.
Why learn Solidity?
Smart contract developers are in demand, and security skills here are especially valuable because bugs can lose real money.
- Familiar syntax: looks like JavaScript, C++ and TypeScript.
- Verifiable: code is public and runs exactly as written.
- Agents and payments: AI agents can hold wallets and call contracts.
Set up and run your first program
Start in the browser with Remix IDE (remix.ethereum.org). For projects, install Foundry, a fast toolkit for compiling, testing and deploying.
curl -L https://foundry.paradigm.xyz | bash
foundryup
forge init hello && cd hello
forge build && forge test// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract Hello {
string public greeting = "Hello, AI! Welcome to Solidity.";
}Contracts, state and types
A contract is like a class whose state variables live permanently on the blockchain. uint256, address, bool and string are common types.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract ModelRegistry {
address public owner;
uint256 public modelCount;
string public latest;
constructor() { owner = msg.sender; }
function register(string calldata name) external {
latest = name;
modelCount += 1;
}
}Functions and visibility
Functions are public, external, internal or private. view reads state and pure touches no state; both are free when called off-chain.
contract Maths {
function params(uint256 layers, uint256 width) public pure returns (uint256) {
return 12 * layers * width * width;
}
uint256 private total;
function add(uint256 x) external { total += x; }
function getTotal() external view returns (uint256) { return total; }
}Mappings, structs and events
mapping is a key-value store. Structs group fields. Events write logs that apps and indexers can listen to.
contract GpuMarket {
struct Listing { address seller; uint256 pricePerHour; bool active; }
mapping(uint256 => Listing) public listings;
uint256 public nextId;
event Listed(uint256 indexed id, address seller, uint256 price);
function list(uint256 price) external returns (uint256 id) {
id = nextId++;
listings[id] = Listing(msg.sender, price, true);
emit Listed(id, msg.sender, price);
}
}Access control and errors
require and custom errors stop invalid calls and undo all changes. Modifiers reuse checks such as "only the owner".
contract Owned {
address public owner = msg.sender;
error NotOwner();
modifier onlyOwner() {
if (msg.sender != owner) revert NotOwner();
_;
}
function transferOwnership(address next) external onlyOwner {
require(next != address(0), "zero address");
owner = next;
}
}Receiving and sending ETH
payable functions accept Ether. Follow checks-effects-interactions: update state before sending funds to prevent reentrancy attacks.
contract Tips {
mapping(address => uint256) public balance;
function tip(address to) external payable {
require(msg.value > 0, "no value");
balance[to] += msg.value;
}
function withdraw() external {
uint256 amount = balance[msg.sender];
balance[msg.sender] = 0; // effect first
(bool ok, ) = payable(msg.sender).call{value: amount}("");
require(ok, "transfer failed"); // then interaction
}
}Solidity and AI
AI and blockchains meet in a few places: AI agents that hold wallets and pay for API calls or compute, on-chain registries for model provenance, oracles that bring off-chain AI results on-chain, and LLM-assisted smart contract auditing. Heavy AI computation never runs on-chain because every node would have to repeat it.
The essential libraries
A model provenance registry
Record the hash of a model's weights so anyone can verify which version produced a result.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
contract ModelProvenance {
struct Model { bytes32 weightsHash; address publisher; uint64 timestamp; }
mapping(string => Model[]) private versions;
event Published(string name, uint256 version, bytes32 weightsHash);
function publish(string calldata name, bytes32 weightsHash) external {
versions[name].push(Model(weightsHash, msg.sender, uint64(block.timestamp)));
emit Published(name, versions[name].length - 1, weightsHash);
}
function verify(string calldata name, uint256 v, bytes32 h) external view returns (bool) {
return versions[name][v].weightsHash == h;
}
}An AI agent that reads a contract
The agent uses web3.py to call view functions on a local Anvil chain as a tool. Read-only calls cost nothing and cannot move funds, which is a safe starting point for on-chain agents.
# anvil & (local chain) then deploy ModelProvenance with forge create
import json
from web3 import Web3
from openai import OpenAI
w3 = Web3(Web3.HTTPProvider("http://127.0.0.1:8545"))
abi = json.load(open("out/ModelProvenance.sol/ModelProvenance.json"))["abi"]
reg = w3.eth.contract(address="0x5FbDB2315678afecb367f032d93F642f64180aa3", abi=abi)
def verify_model(name, version, sha256_hex):
return str(reg.functions.verify(name, version, bytes.fromhex(sha256_hex)).call())
client = OpenAI(base_url="http://localhost:11434/v1", api_key="ollama")
tools = [{"type": "function", "function": {"name": "verify_model", "description": "Check a model hash against the on-chain registry",
"parameters": {"type": "object", "properties": {"name": {"type": "string"}, "version": {"type": "integer"},
"sha256_hex": {"type": "string"}}, "required": ["name", "version", "sha256_hex"]}}}]
messages = [{"role": "user", "content": "Is version 0 of 'tc-llm' the weights with hash " + "ab" * 32 + "?"}]
for _ in range(5):
msg = client.chat.completions.create(model="llama3.1", messages=messages, tools=tools).choices[0].message
messages.append(msg)
if not msg.tool_calls:
print(msg.content); break
for c in msg.tool_calls:
messages.append({"role": "tool", "tool_call_id": c.id, "content": verify_model(**json.loads(c.function.arguments))})Never give an AI agent a private key with real funds without strict limits and human approval.
ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.Solidity learning roadmap
Tick items off as you go. Your progress is saved in this browser.
Beginner
Intermediate
Advanced
Projects to build
Solidity cheat sheet
| Task | Syntax |
|---|---|
| Version | pragma solidity ^0.8.24; |
| State var | uint256 public count; |
| Function | function f(uint x) external returns (uint) |
| Mapping | mapping(address => uint) bal; |
| Check | require(x > 0, "msg"); |
| Event | emit Done(id); |
Common mistakes
- Sending funds before updating state opens reentrancy attacks.
- Every write costs gas; loops over large arrays can make functions unusable.
- Deployed code cannot be changed; test and audit before mainnet.
Where to go next
- Solidity docs — official
- Foundry Book — toolkit
- OpenZeppelin Contracts — secure building blocks
On TensorCore.si: JavaScript volume, TypeScript volume.
Keyboard: [ previous language · ] next language · / search the library