---
title: Syscalls
description: Reference the public C syscall wrappers for state mutation,
  logging, CPI, memory, and exit.
source_url:
  html: https://thru.org/docs/sdks/c-reference/syscalls/
  md: https://thru.org/docs/sdks/c-reference/syscalls.md
---

# Syscalls

Use this page when you need the low-level mutation and control operations exposed by `tn_sdk_syscall.h`.

## Return convention

Most syscall wrappers return a `ulong` status code in `a0`.

The main exception is `tsys_invoke`, which has two result channels:

- return value: syscall-level success or failure
- `invoke_err_code`: callee-level success or failure

`tsys_exit` never returns.

## Account and balance syscalls

### `tsys_set_account_data_writable`

```c
ulong tsys_set_account_data_writable( ulong account_idx );
```

Mark an account’s data segment as writable. Must be called before writing to `tsdk_get_account_data_ptr(...)`. Returns `TSDK_SUCCESS` on success.

### `tsys_account_transfer`

```c
ulong tsys_account_transfer( ulong from_account_idx, ulong to_account_idx,
                             ulong amount );
```

Transfer `amount` native tokens from one account to another. Both indices must be valid and the source account must be authorized.

### `tsys_account_create`

```c
ulong tsys_account_create( ulong account_idx, uchar const seed[TN_SEED_SIZE],
                           void const * proof, ulong proof_sz );
```

Create a program-defined account. The 32-byte `seed` determines the account address deterministically. The `proof` is a state proof validating the account does not already exist.

### `tsys_account_create_ephemeral`

```c
ulong tsys_account_create_ephemeral( ulong account_idx,
                                     uchar const seed[TN_SEED_SIZE] );
```

Create a transaction-scoped ephemeral account. No state proof required because ephemeral accounts do not persist across transactions.

### `tsys_account_create_eoa`

```c
ulong tsys_account_create_eoa( ulong account_idx,
                               tn_signature_t const * signature,
                               void const * proof, ulong proof_sz );
```

Create an externally owned account (EOA). Requires a valid signature and state proof.

### `tsys_account_delete`

```c
ulong tsys_account_delete( ulong account_idx );
```

Delete an account. The account must be owned by the current program.

### `tsys_account_resize`

```c
ulong tsys_account_resize( ulong account_idx, ulong new_size );
```

Resize an account’s data region to `new_size` bytes. Maximum size is `TSDK_ACCOUNT_DATA_SZ_MAX` (16 MB). The account must already be writable.

### `tsys_account_set_flags`

```c
ulong tsys_account_set_flags( ushort account_idx, uchar flags );
```

Update the account’s flags byte. See [Accounts and Transaction Context](https://thru.org/docs/sdks/c-reference/accounts-and-transaction-context.md) for flag constants.

### `tsys_account_compress`

```c
ulong tsys_account_compress( ulong account_idx, void const * proof,
                             ulong proof_sz );
```

Compress an account’s state, removing it from the active ledger while preserving a proof of its existence.

### `tsys_account_decompress`

```c
ulong tsys_account_decompress( ulong account_idx, void const * meta,
                               void const * data, void const * proof,
                               ulong proof_sz );
```

Decompress a previously compressed account by providing its metadata, data payload, and validity proof.

## Invocation, logging, and exit

### `tsys_invoke`

```c
ulong tsys_invoke( void const * instr_data, ulong instr_data_sz,
                   ushort program_account_idx,
                   tsdk_invoke_auth_t const * auth,
                   ulong * invoke_err_code );
```

Cross-program invocation. Returns a syscall-level status in the return value and a callee-level status in `invoke_err_code`. Pass `NULL` for `auth` when no explicit authorization is needed. See [Cross-Program Invocation](https://thru.org/docs/sdks/c-reference/cross-program-invocation.md) for details.

### `tsys_log`

```c
ulong tsys_log( void const * data, ulong data_len );
```

Emit raw log bytes. `tsdk_printf` is a formatted wrapper around this (capped at 1024 bytes per call).

### `tsys_emit_event`

```c
ulong tsys_emit_event( void const * data, ulong data_sz );
```

Emit an event payload that downstream consumers can read from the transaction result.

### `tsys_exit`

```c
ulong __attribute__(( noreturn )) tsys_exit( ulong exit_code, ulong revert );
```

Terminate execution. If `revert` is non-zero, the transaction state is rolled back. Prefer `tsdk_return` or `tsdk_revert` unless you need direct control.

## Anonymous segment syscalls

These are lower-level memory-management syscalls that most programs will not need immediately.

### `tsys_set_anonymous_segment_sz`

```c
ulong tsys_set_anonymous_segment_sz( void * addr );
```

Set the anonymous (heap) segment size to `addr`.

### `tsys_increment_anonymous_segment_sz`

```c
ulong tsys_increment_anonymous_segment_sz( void * segment_addr, ulong delta,
                                           void ** addr );
```

Grow an anonymous segment by `delta` bytes and optionally receive the resulting address in `addr`.

## Typical mutation flow

```c
ushort account_idx = 2U;

if( !tsdk_is_account_idx_valid( account_idx ) ) tsdk_revert( 1UL );

if( tsys_set_account_data_writable( account_idx ) != TSDK_SUCCESS ) {
  tsdk_revert( 2UL );
}

if( tsys_account_resize( account_idx, 128UL ) != TSDK_SUCCESS ) {
  tsdk_revert( 3UL );
}
```

## Practical guidance

- Call `tsys_set_account_data_writable` before writing account bytes.
- Validate account indices before every syscall that takes an index from instruction data.
- Treat proof-carrying syscalls as layout-sensitive. Validate sizes before forwarding raw payload tails.
- Use `tsdk_printf` for human-readable debugging and `tsys_emit_event` for machine-consumed event payloads.

## Notes

- `tsys_invoke` is the only wrapper here that can both return a syscall status and a callee status.
- The C wrapper performs extra auth validation before issuing the CPI syscall, so bad auth descriptors can revert locally before the callee runs.
