---
title: Introspection
---

To smooth interoperability, often standards require smart contracts to implement [introspection mechanisms](https://en.wikipedia.org/wiki/Type_introspection).

In Ethereum, the [EIP165](https://eips.ethereum.org/EIPS/eip-165) standard defines how contracts should declare
their support for a given interface, and how other contracts may query this support.

Starknet offers a similar mechanism for interface introspection defined by the [SRC5](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md) standard.

## SRC5

Similar to its Ethereum counterpart, the [SRC5](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md) standard requires contracts to implement the `supports_interface` function,
which can be used by others to query if a given interface is supported.

### Usage

To expose this functionality, the contract must implement the [SRC5Component](/contracts-cairo/3.x/api/introspection#SRC5Component), which defines the `supports_interface` function.
Here is an example contract:

```rust
#[starknet::contract]
mod MyContract {
    use openzeppelin_introspection::src5::SRC5Component;

    component!(path: SRC5Component, storage: src5, event: SRC5Event);

    #[abi(embed_v0)]
    impl SRC5Impl = SRC5Component::SRC5Impl<ContractState>;
    impl SRC5InternalImpl = SRC5Component::InternalImpl<ContractState>;

    #[storage]
    struct Storage {
        #[substorage(v0)]
        src5: SRC5Component::Storage
    }

    #[event]
    #[derive(Drop, starknet::Event)]
    enum Event {
        #[flat]
        SRC5Event: SRC5Component::Event
    }

    #[constructor]
    fn constructor(ref self: ContractState) {
        self.src5.register_interface(selector!("some_interface"));
    }
}
```

### Interface

```rust
#[starknet::interface]
pub trait ISRC5 {
    /// Query if a contract implements an interface.
    /// Receives the interface identifier as specified in SRC-5.
    /// Returns `true` if the contract implements `interface_id`, `false` otherwise.
    fn supports_interface(interface_id: felt252) -> bool;
}
```

## Computing the interface ID

The interface ID, as specified in the standard, is the [XOR](https://en.wikipedia.org/wiki/Exclusive_or) of all the
[Extended Function Selectors](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md#extended-function-selector)
of the interface. We strongly advise reading the SNIP to understand the specifics of computing these
extended function selectors. There are tools such as [src5-rs](https://github.com/ericnordelo/src5-rs) that can help with this process.

## Registering interfaces

For a contract to declare its support for a given interface, we recommend using the SRC5 component to register support upon contract deployment through a constructor either directly or indirectly (as an initializer) like this:

```rust
#[starknet::contract]
mod MyContract {
    use openzeppelin_interfaces::accounts as interface;
    use openzeppelin_introspection::src5::SRC5Component;

    component!(path: SRC5Component, storage: src5, event: SRC5Event);

    #[abi(embed_v0)]
    impl SRC5Impl = SRC5Component::SRC5Impl<ContractState>;
    impl InternalImpl = SRC5Component::InternalImpl<ContractState>;

    #[storage]
    struct Storage {
        #[substorage(v0)]
        src5: SRC5Component::Storage
    }

    #[event]
    #[derive(Drop, starknet::Event)]
    enum Event {
        #[flat]
        SRC5Event: SRC5Component::Event
    }

    #[constructor]
    fn constructor(ref self: ContractState) {
        // Register the contract's support for the ISRC6 interface
        self.src5.register_interface(interface::ISRC6_ID);
    }

    (...)
}
```

## Querying interfaces

Use the `supports_interface` function to query a contract’s support for a given interface.

```rust
#[starknet::contract]
mod MyContract {
    use openzeppelin_interfaces::accounts as interface;
    use openzeppelin_interfaces::introspection::ISRC5DispatcherTrait;
    use openzeppelin_interfaces::introspection::ISRC5Dispatcher;
    use starknet::ContractAddress;

    #[storage]
    struct Storage {}

    #[external(v0)]
    fn query_is_account(self: @ContractState, target: ContractAddress) -> bool {
        let dispatcher = ISRC5Dispatcher { contract_address: target };
        dispatcher.supports_interface(interface::ISRC6_ID)
    }
}
```

<Callout>
If you are unsure whether a contract implements SRC5 or not, you can follow the process described in
[here](https://github.com/starknet-io/SNIPs/blob/main/SNIPS/snip-5.md#how-to-detect-if-a-contract-implements-src-5).
</Callout>
