Contract ABI
Contract ABI is a representation of a Starknet contract’s interface. It is formatted as JSON and describes the functions, structs and events which are defined in the contract.
You can get the contract’s ABI by compiling:
cargo run --bin starknet-compile -- /path/to/input.cairo /path/to/output.json
The Cairo 0 compiler is no longer maintained, see here for more details on Cairo 1 contracts compilation. |
The following is an example contract ABI:
-
Cairo v1
-
Cairo v2
[
{
"type": "function",
"name": "constructor",
"inputs": [
{
"name": "name_",
"type": "core::felt252"
},
{
"name": "symbol_",
"type": "core::felt252"
},
{
"name": "decimals_",
"type": "core::integer::u8"
},
{
"name": "initial_supply",
"type": "core::integer::u256"
},
{
"name": "recipient",
"type": "core::starknet::contract_address::ContractAddress"
}
],
"outputs": [],
"state_mutability": "external"
},
{
"type": "function",
"name": "get_name",
"inputs": [],
"outputs": [
{
"type": "core::felt252"
}
],
"state_mutability": "view"
},
{
"type": "function",
"name": "get_symbol",
"inputs": [],
"outputs": [
{
"type": "core::felt252"
}
],
"state_mutability": "view"
},
{
"type": "function",
"name": "get_decimals",
"inputs": [],
"outputs": [
{
"type": "core::integer::u8"
}
],
"state_mutability": "view"
},
{
"type": "function",
"name": "get_total_supply",
"inputs": [],
"outputs": [
{
"type": "core::integer::u256"
}
],
"state_mutability": "view"
},
{
"type": "function",
"name": "balance_of",
"inputs": [
{
"name": "account",
"type": "core::starknet::contract_address::ContractAddress"
}
],
"outputs": [
{
"type": "core::integer::u256"
}
],
"state_mutability": "view"
},
{
"type": "function",
"name": "allowance",
"inputs": [
{
"name": "owner",
"type": "core::starknet::contract_address::ContractAddress"
},
{
"name": "spender",
"type": "core::starknet::contract_address::ContractAddress"
}
],
"outputs": [
{
"type": "core::integer::u256"
}
],
"state_mutability": "view"
},
{
"type": "function",
"name": "transfer",
"inputs": [
{
"name": "recipient",
"type": "core::starknet::contract_address::ContractAddress"
},
{
"name": "amount",
"type": "core::integer::u256"
}
],
"outputs": [],
"state_mutability": "external"
},
{
"type": "function",
"name": "transfer_from",
"inputs": [
{
"name": "sender",
"type": "core::starknet::contract_address::ContractAddress"
},
{
"name": "recipient",
"type": "core::starknet::contract_address::ContractAddress"
},
{
"name": "amount",
"type": "core::integer::u256"
}
],
"outputs": [],
"state_mutability": "external"
},
{
"type": "function",
"name": "approve",
"inputs": [
{
"name": "spender",
"type": "core::starknet::contract_address::ContractAddress"
},
{
"name": "amount",
"type": "core::integer::u256"
}
],
"outputs": [],
"state_mutability": "external"
},
{
"type": "function",
"name": "increase_allowance",
"inputs": [
{
"name": "spender",
"type": "core::starknet::contract_address::ContractAddress"
},
{
"name": "added_value",
"type": "core::integer::u256"
}
],
"outputs": [],
"state_mutability": "external"
},
{
"type": "function",
"name": "decrease_allowance",
"inputs": [
{
"name": "spender",
"type": "core::starknet::contract_address::ContractAddress"
},
{
"name": "subtracted_value",
"type": "core::integer::u256"
}
],
"outputs": [],
"state_mutability": "external"
},
{
"type": "event",
"name": "Transfer",
"inputs": [
{
"name": "from",
"type": "core::starknet::contract_address::ContractAddress"
},
{
"name": "to",
"type": "core::starknet::contract_address::ContractAddress"
},
{
"name": "value",
"type": "core::integer::u256"
}
]
},
{
"type": "event",
"name": "Approval",
"inputs": [
{
"name": "owner",
"type": "core::starknet::contract_address::ContractAddress"
},
{
"name": "spender",
"type": "core::starknet::contract_address::ContractAddress"
},
{
"name": "value",
"type": "core::integer::u256"
}
]
}
]
[
{
"type": "impl",
"name": "CounterContract",
"interface_name": "new_syntax_test_contract::new_syntax_test_contract::ICounterContract"
},
{
"type": "interface",
"name": "new_syntax_test_contract::new_syntax_test_contract::ICounterContract",
"items": [
{
"type": "function",
"name": "increase_counter",
"inputs": [
{
"name": "amount",
"type": "core::integer::u128"
}
],
"outputs": [],
"state_mutability": "external"
},
{
"type": "function",
"name": "decrease_counter",
"inputs": [
{
"name": "amount",
"type": "core::integer::u128"
}
],
"outputs": [],
"state_mutability": "external"
},
{
"type": "function",
"name": "get_counter",
"inputs": [],
"outputs": [
{
"type": "core::integer::u128"
}
],
"state_mutability": "view"
}
]
},
{
"type": "constructor",
"name": "constructor",
"inputs": [
{
"name": "initial_counter",
"type": "core::integer::u128"
},
{
"name": "other_contract_addr",
"type": "core::starknet::contract_address::ContractAddress"
}
]
},
{
"type": "event",
"name": "new_syntax_test_contract::new_syntax_test_contract::counter_contract::CounterIncreased",
"kind": "struct",
"members": [
{
"name": "amount",
"type": "core::integer::u128",
"kind": "data"
}
]
},
{
"type": "event",
"name": "new_syntax_test_contract::new_syntax_test_contract::counter_contract::CounterDecreased",
"kind": "struct",
"members": [
{
"name": "amount",
"type": "core::integer::u128",
"kind": "data"
}
]
},
{
"type": "event",
"name": "new_syntax_test_contract::new_syntax_test_contract::counter_contract::Event",
"kind": "enum",
"variants": [
{
"name": "CounterIncreased",
"type": "new_syntax_test_contract::new_syntax_test_contract::counter_contract::CounterIncreased",
"kind": "nested"
},
{
"name": "CounterDecreased",
"type": "new_syntax_test_contract::new_syntax_test_contract::counter_contract::CounterDecreased",
"kind": "nested"
}
]
}
]
Cairo v2 ABI changes
With the transition to v2, the contract ABI underwent some changes. Consider the following high level code that generates the ABI in the above example:
#[starknet::interface]
trait IOtherContract<TContractState> {
fn decrease_allowed(self: @TContractState) -> bool;
}
#[starknet::interface]
trait ICounterContract<TContractState> {
fn increase_counter(ref self: TContractState, amount: u128);
fn decrease_counter(ref self: TContractState, amount: u128);
fn get_counter(self: @TContractState) -> u128;
}
#[starknet::contract]
mod counter_contract {
use starknet::ContractAddress;
use super::{
IOtherContractDispatcher, IOtherContractDispatcherTrait, IOtherContractLibraryDispatcher
};
#[storage]
struct Storage {
counter: u128,
other_contract: IOtherContractDispatcher
}
#[event]
#[derive(Drop, starknet::Event)]
enum Event {
CounterIncreased: CounterIncreased,
CounterDecreased: CounterDecreased
}
#[derive(Drop, starknet::Event)]
struct CounterIncreased {
amount: u128
}
#[derive(Drop, starknet::Event)]
struct CounterDecreased {
amount: u128
}
#[constructor]
fn constructor(
ref self: ContractState, initial_counter: u128, other_contract_addr: ContractAddress
) {
self.counter.write(initial_counter);
self
.other_contract
.write(IOtherContractDispatcher { contract_address: other_contract_addr });
}
#[external(v0)]
impl CounterContract of super::ICounterContract<ContractState> {
fn get_counter(self: @ContractState) -> u128 {
self.counter.read()
}
fn increase_counter(ref self: ContractState, amount: u128) {
let current = self.counter.read();
self.counter.write(current + amount);
self.emit(CounterIncreased { amount });
}
fn decrease_counter(ref self: ContractState, amount: u128) {
let allowed = self.other_contract.read().decrease_allowed();
if allowed {
let current = self.counter.read();
self.counter.write(current - amount);
self.emit(CounterDecreased { amount });
}
}
}
}
Interface and Impl ABI entries
Since the CounterContract
impl is annotated with the #[external(v0)]
attribute, you’ll find the following impl
entry in the ABI:
{
"type": "impl",
"name": "CounterContract",
"interface_name": "new_syntax_test_contract::new_syntax_test_contract::ICounterContract"
},
This means that every function appearing in the ICounterContract
interface
is a possible entry point of the contract.
Standalone functions in the contract (outside an external impl) can also be anotated with |
Events
In Cairo v2, a dedicated type for the contract’s events was introduced. Currently, the contract event type must be an enum named Event
, whose variants are structs of the same name as the variant. Types that can be emitted via self.emit(_)
must implement the Event
trait, which defines how this type should be serialized into two felt252
arrays, keys
and data
.
The Event
enum variants appear in the ABI under "type" = "event"
rather than regular structs. For such entries, each member has an additional kind
field which specifies how the serialization into keys and data takes place:
-
if the kind is
key
, then this member or variant are serialized into the event’s keys -
if the kind is
data
, then this member or variant are serialized into the event’s data -
if the kind is
nested
, then the member or variant are serialized acording to theEvent
attribute, potentially adding to both keys and data. At the moment, this feature is not yet supported, so no high level code written in Cairo v2.0.0 can generate such ABI.
Specification
You can find a JSON schema specification of the ABI in the starknet-specs repository. For a UI-friendly version, you can use the OPEN-RPC playground.