System Calls

Writing smart contracts requires various associated operations, such as calling another contract or accessing the contract’s storage, that standalone programs do not require. The Starknet contract language supports these operations by using system calls. System calls enable a contract to require services from the Starknet OS. You can use system calls in a function to get information that depends on the broader state of Starknet, which would otherwise be inaccessible, rather than local variables that appear in the function’s scope.

get_block_hash

Function signature

extern fn get_block_hash_syscall(
    block_number: u64
) -> SyscallResult<felt252> implicits(GasBuiltin, System) nopanic;

Description

Gets the hash of a specific Starknet block within the range of [first_v0_12_0_block, current_block - 10].

Arguments

block_number: u64

The number of the block whose hash you want to get.

Return values

The hash of the specified block.

Common library

Error messages

Block number out of range

block_number is greater than current_block - 10.

0

block_number is less than the first block number of v0.12.0.

get_execution_info

Function signature

extern fn get_execution_info_syscall() -> SyscallResult<Box<starknet::info::ExecutionInfo>> implicits(
    GasBuiltin, System
) nopanic;

Description

Gets information about the currently executing block and the transactions in the block. For a complete description of this information, see Execution information

This single system call contains all information for a block, transaction, and execution context.

When an account’s __validate__, __validate_deploy__, or __validate_declare__ function calls get_execution_info, the return values for block_timestamp and block_number are modified as follows:

  • block_timestamp returns the hour, rounded down to the nearest hour.

  • block_number returns the block number, rounded down to the nearest multiple of 100.

Arguments

None.

Return values

ExecutionInfo

A struct that contains information about the currently executing function, transaction, and block.

Common library

Example

This example shows how to pull the block number from the ExecutionInfo struct.

let execution_info = get_execution_info().unbox();
let block_info = execution_info.block_info.unbox();
let block number = block_info.block_number;

call_contract

Function signature

extern fn call_contract_syscall(
    address: ContractAddress, entry_point_selector: felt252, calldata: Span<felt252>
) -> SyscallResult<Span<felt252>> implicits(GasBuiltin, System) nopanic;

Description

Calls a given contract. This system call expects the address of the called contract, a selector for a function within that contract, and call arguments.

An internal call can’t return Err(_) as this is not handled by the sequencer and the Starknet OS.

If call_contract_syscall fails, this can’t be caught and will therefore result in the entire transaction being reverted.

Arguments

address: ContractAddress

The address of the contract you want to call.

entry_point_selector: felt252

A selector for a function within that contract.

calldata: Span<felt252>

The calldata array.

Return values

  • The call response, of type SyscallResult<Span<felt252>>.

Common library

This is considered a lower-level syntax for calling contracts.

If the interface of the called contract is available, then you can use a more straightforward syntax.

deploy

Function signature

extern fn deploy_syscall(
    class_hash: ClassHash,
    contract_address_salt: felt252,
    calldata: Span<felt252>,
    deploy_from_zero: bool,
) -> SyscallResult<(ContractAddress, Span::<felt252>)> implicits(GasBuiltin, System) nopanic;

Description

Deploys a new instance of a previously declared class.

Arguments

class_hash: ClassHash

The class hash of the contract to be deployed.

contract_address_salt: felt252

The salt, an arbitrary value provided by the sender, used in the computation of the contract’s address.

calldata: Span<felt252>

The constructor’s calldata. An array of felts.

deploy_from_zero: bool

A flag that determines whether the deployer’s address affects the computation of the contract address. When not set, or when set to FALSE, the caller address is used as the new contract’s deployer address. When set to TRUE, 0 is used.

Return values

  • A tuple wrapped with SyscallResult where:

    • The first element is the address of the deployed contract, of type ContractAddress.

    • The second element is the response array from the contract’s constructor, of type Span::<felt252>.

Common library

emit_event

Function signature

extern fn emit_event_syscall(
    keys: Span<felt252>, data: Span<felt252>
) -> SyscallResult<()> implicits(GasBuiltin, System) nopanic;

Description

Emits an event with a given set of keys and data.

For more information, and for a higher-level syntax for emitting events, see Starknet events.

Arguments

keys: Span<felt252>

The event’s keys. These are analogous to Ethereum’s event topics, you can use the starknet_getEvents method to filter by these keys.

data: Span<felt252>

The event’s data.

Return values

None.

Common library

Example

The following example emits an event with two keys, the strings key and deposit and three data elements: 1, 2, and 3.

let keys = array!['key', 'deposit'];
let values = array![1, 2, 3];
emit_event_syscall(keys, values).unwrap_syscall();

library_call

Function signature

extern fn library_call_syscall(
    class_hash: ClassHash, function_selector: felt252, calldata: Span<felt252>
) -> SyscallResult<Span<felt252>> implicits(GasBuiltin, System) nopanic;

Description

Calls the requested function in any previously declared class. The class is only used for its logic.

This system call replaces the known delegate call functionality from Ethereum, with the important difference that there is only one contract involved.

Arguments

class_hash: ClassHash

The hash of the class you want to use.

function_selector: felt252

A selector for a function within that class.

calldata: Span<felt252>

The calldata.

Return values

  • The call response, of type SyscallResult<Span<felt252>>.

Common library

send_message_to_L1

Function signature

extern fn send_message_to_l1_syscall(
    to_address: felt252, payload: Span<felt252>
) -> SyscallResult<()> implicits(GasBuiltin, System) nopanic;

Description

Sends a message to L1.

This system call includes the message parameters as part of the proof’s output and exposes these parameters to the Starknet Core Contract on L1 once the state update, including the transaction, is received.

For more information, see Starknet’s messaging mechanism.

Arguments

to_address: felt252

The recipient’s L1 address.

payload: Span<felt252>

The array containing the message payload

Return values

None.

Common library

Example

The following example sends a message whose content is (1,2) to the L1 contract whose address is 3423542542364363.

let payload = ArrayTrait::new();
payload.append(1);
payload.append(2);
send_message_to_l1_syscall(payload).unwrap_syscall();

replace_class

Function signature

extern fn replace_class_syscall(
    class_hash: ClassHash
) -> SyscallResult<()> implicits(GasBuiltin, System) nopanic;

Description

Once replace_class is called, the class of the calling contract (i.e. the contract whose address is returned by get_contract_address at the time the syscall is called) will be replaced by the class whose hash is given by the class_hash argument.

After calling replace_class, the code currently executing from the old class will finish running.

The new class will be used from the next transaction onwards or if the contract is called via the call_contract syscall in the same transaction (after the replacement).

Arguments

class_hash_: ClassHash

The hash of the class you want to use as a replacement.

Return values

None.

Common library

storage_read

Function signature

extern fn storage_read_syscall(
    address_domain: u32, address: StorageAddress
) -> SyscallResult<felt252> implicits(GasBuiltin, System) nopanic;

Description

Gets the value of a key in the storage of the calling contract.

This system call provides direct access to any possible key in storage, in contrast with var.read(), which enables you to read storage variables that are defined explicitly in the contract.

For information on accessing storage by using the storage variables, see storage variables.

Arguments

address_domain: u32

The domain of the key, used to separate between different data availability modes. This separation is used in Starknet to offer different data availability modes. Currently, only the onchain mode (where all updates go to L1), indicated by domain 0, is supported. Other address domains which will be introduced in the future will behave differently in terms of publication (in particular, they will not be posted on L1, creating a tradeoff between cost and security).

address: StorageAddress

The requested storage address.

Return values

  • The value of the key, of type SyscallResult<felt252>.

Common library

Example

use starknet::storage_access::storage_base_address_from_felt252;

...

let storage_address = storage_base_address_from_felt252(3534535754756246375475423547453)
storage_read_syscall(0, storage_address).unwrap_syscall()

storage_write

Function signature

extern fn storage_write_syscall(
    address_domain: u32, address: StorageAddress, value: felt252
) -> SyscallResult<()> implicits(GasBuiltin, System) nopanic;

Description

Sets the value of a key in the storage of the calling contract.

This system call provides direct access to any possible key in storage, in contrast with var.write(), which enables you to write to storage variables that are defined explicitly in the contract.

For information on accessing storage by using the storage variables, see storage variables.

Arguments

address_domain: u32

The domain of the key, used to separate between different data availability modes. This separation is used in Starknet to offer different data availability modes. Currently, only the onchain mode (where all updates go to L1), indicated by domain 0, is supported. Other address domains which will be introduced in the future will behave differently in terms of publication (in particular, they will not be posted on L1, creating a tradeoff between cost and security).

address: StorageAddress

The requested storage address.

value: felt252

The value to write to the key.

Return values

None.

Common library

syscalls.cairo

keccak

Function signature

extern fn keccak_syscall(
    data: Span<felt252>
) -> SyscallResult<u256> implicits(GasBuiltin, System) nopanic;

Description

Computes the Keccak-256 hash of the input data.

This system call is particularly useful when interacting with Ethereum contracts or implementing Ethereum-compatible functionality, as Keccak-256 is widely used in the Ethereum ecosystem.

Instead of using this syscall directly, it is recommended to use the functions provided in keccak.cairo which provide a more convenient interface and handle the syscall under the hood.

Arguments

data: Span<felt252>

The input data to be hashed, represented as an array of field elements.

Return values

  • The Keccak-256 hash of the input data as a u256 value.

Common library

Example

The following example demonstrates how to compute a Keccak-256 hash using the recommended functions from keccak.cairo:

use array::ArrayTrait;
use keccak::keccak_u256s_le_inputs;

// Create input data
let mut data = ArrayTrait::new();
data.append(1_u256);
data.append(2_u256);

// Compute Keccak hash using the recommended function
let hash = keccak_u256s_le_inputs(data.span());

secp256r1

Various systems calls for computations over the secp256r1 curve (also known as NIST P-256).

These system calls are particularly useful when implementing traditional PKI or secure communication functionality, as secp256r1 is widely used in TLS, secure messaging, and government standards.

Instead of using these syscalls directly, it is recommended to use the traits and implementations of the corelib’s secp256r1 module which provides a more convenient interface and handles them for you.

secp256r1_new

Function signature

extern fn secp256r1_new_syscall(
    x: u256, y: u256
) -> SyscallResult<Option<Secp256r1Point>> implicits(GasBuiltin, System) nopanic;

Description

Creates a new point on the secp256r1 curve from its x and y coordinates.

Arguments

x: u256

The x-coordinate of the point.

y: u256

The y-coordinate of the point.

Return values

Returns Some(point) if the coordinates represent a valid point on the curve, None otherwise.

Common library

Example

The following example demonstrates how to create a new point on the secp256r1 curve:

use starknet::secp256r1::Secp256r1Point;

// Known valid point coordinates on secp256r1 curve (generator point)
let x = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296_u256;
let y = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5_u256;

// Create a new point using the recommended function
let point = secp256r1_new_syscall(x, y).unwrap_syscall();
match point {
    Option::Some(p) => {
        // Point is valid and can be used for further operations
        // For example, you could get its coordinates back:
        let (px, py) = secp256r1_get_xy_syscall(p).unwrap_syscall();
    },
    Option::None => {
        // Point was not on the curve
    }
}

secp256r1_add

Function signature

extern fn secp256r1_add_syscall(
    p0: Secp256r1Point, p1: Secp256r1Point,
) -> SyscallResult<Secp256r1Point> implicits(GasBuiltin, System) nopanic;

Description

Adds two points on the secp256r1 curve.

Arguments

p0: Secp256r1Point

The first point on the curve.

p1: Secp256r1Point

The second point on the curve.

Return values

The resulting point from adding p0 and p1.

Common library

Example

The following example demonstrates how to add two points on the secp256r1 curve:

use starknet::secp256r1::Secp256r1Point;

// Create two points to add (using generator point)
let x = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296_u256;
let y = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5_u256;

// Create first point
let point1 = secp256r1_new_syscall(x, y).unwrap_syscall().expect('Invalid point1');
// Create second point (using same point for example)
let point2 = secp256r1_new_syscall(x, y).unwrap_syscall().expect('Invalid point2');

// Add the points
let sum = secp256r1_add_syscall(point1, point2).unwrap_syscall();

// Get the resulting coordinates
let (sum_x, sum_y) = secp256r1_get_xy_syscall(sum).unwrap_syscall();

secp256r1_mul

Function signature

extern fn secp256r1_mul_syscall(
    p: Secp256r1Point, scalar: u256,
) -> SyscallResult<Secp256r1Point> implicits(GasBuiltin, System) nopanic;

Description

Multiplies a point on the secp256r1 curve by a scalar value.

Arguments

p: Secp256r1Point

The point to be multiplied.

scalar: u256

The scalar value to multiply the point by.

Return values

The resulting point from the scalar multiplication.

Common library

Example

The following example demonstrates how to multiply a point by a scalar on the secp256r1 curve:

use starknet::secp256r1::Secp256r1Point;

// Create a point to multiply (using generator point)
let x = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296_u256;
let y = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5_u256;

// Create the point
let point = secp256r1_new_syscall(x, y).unwrap_syscall().expect('Invalid point');

// Multiply point by scalar
let scalar = 0x2_u256;  // Example scalar value of 2
let product = secp256r1_mul_syscall(point, scalar).unwrap_syscall();

// Get the resulting coordinates
let (product_x, product_y) = secp256r1_get_xy_syscall(product).unwrap_syscall();

secp256r1_get_point_from_x

Function signature

extern fn secp256r1_get_point_from_x_syscall(
    x: u256, y_parity: bool,
) -> SyscallResult<Option<Secp256r1Point>> implicits(GasBuiltin, System) nopanic;

Description

Recovers a point on the curve given its x-coordinate and y-parity. Since the secp256r1 curve has an even and an odd solution for y given x, the y_parity parameter determines which y value to use.

Arguments

x: u256

The x-coordinate of the point.

y_parity: bool

If true, choose the odd y value; if false, choose the even y value.

Return values

Returns Some(point) if a point exists with the given x coordinate, None otherwise.

Common library

Example

The following example demonstrates how to recover a point from its x-coordinate and y-parity:

use starknet::secp256r1::Secp256r1Point;

// Known x-coordinate of a valid point (generator point x-coordinate)
let x = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296_u256;
let y_is_odd = false;

// Recover the point
let point = secp256r1_get_point_from_x_syscall(x, y_is_odd).unwrap_syscall();
match point {
    Option::Some(p) => {
        // Point was successfully recovered
        let (recovered_x, recovered_y) = secp256r1_get_xy_syscall(p).unwrap_syscall();
        assert(recovered_x == x, 'x coordinate mismatch');
    },
    Option::None => {
        // No point exists with this x-coordinate
        panic!('Point recovery failed')
    }
}

secp256r1_get_xy

Function signature

extern fn secp256r1_get_xy_syscall(
    p: Secp256r1Point,
) -> SyscallResult<(u256, u256)> implicits(GasBuiltin, System) nopanic;

Description

Returns the coordinates of a point on the secp256r1 curve.

Arguments

Return values

A tuple containing the x and y coordinates of the point.

Common library

Example

The following example demonstrates how to get the coordinates of a point on the secp256r1 curve:

use starknet::secp256r1::Secp256r1Point;

// Create a point to extract coordinates from (using generator point)
let x = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296_u256;
let y = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5_u256;

// Create the point
let point = secp256r1_new_syscall(x, y).unwrap_syscall().expect('Invalid point');

// Get the coordinates
let (point_x, point_y) = secp256r1_get_xy_syscall(point).unwrap_syscall();

// Verify the coordinates match the original values
assert(point_x == x, 'x coordinate mismatch');
assert(point_y == y, 'y coordinate mismatch');