# Starknet Standard Interface Detection

**URL:** <https://community.starknet.io/t/starknet-standard-interface-detection/92664>\
**Category:** SNIPs\
**Created:** [May 16, 2023, 12:54pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664 "2023-05-16T12:54:02Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![ericnordelo](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/ericnordelo/32/1371_2.png) [@ericnordelo](https://community.starknet.io/u/ericnordelo)\
**Post date:** [May 16, 2023, 12:54pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/1 "2023-05-16T12:54:02Z")

</div>

Having the ability to check if a smart contract implements a specific interface is a very important feature that supports interoperability patterns (ERC721 transferFrom, etc…). In the Ethereum ecosystem, the ERC165 specifies the “how to”, and is widely used as one of the oldest standards. In Starknet, some implementations have somehow used this Ethereum Standard for defining interface ids (like Account implementors), for being able to implement ERCs that depend on it, but there’s a lack of a formal definition, and Cairo types have been mapped to Solidity types on the fly. In the beginning, with Cairo 0 this formalization was unpractical because the language itself was likely to change a lot, but now we have achieved certain maturity with Cairo 1, which I think allows us to define in the right way this process of interface ids generation.

I propose defining an SNIP from the ERC-165 idea, but using Cairo types instead. While in the past we’ve used these Solidity types for the interface generation (Account example):

```auto
interface IAccount {

    struct Call {
        address to;
        bytes4 selector;
        bytes data;
    }

    function supports_interface(bytes4) external;
    function is_valid_signature(bytes32, bytes32[] calldata) external;
    function __execute__ (Call[] calldata) external;
    function __validate__ (Call[] calldata) external;
    function __validate_declare__ (bytes32) external;
}

```

One of the problems with this is that for example, we would obtain the same interface for a param being `Span<T>` or `Array<T>`, and we would need to define if we use `bytes32` or `uint256` from Solidity when we have the `u256` type in Cairo.

I propose having something like this:

```auto
struct Call {
    to: ContractAddress,
    selector: u32,
    calldata: Array<felt252>
}

trait IAccount {
    fn supports_interface(u32);
    fn is_valid_signature(felt252, Array<felt252>);
    fn __execute__ (Array<Call>);
    fn __validate__ (Array<Call>);
    fn __validate_declare__ (felt252);
}

```

Translated into this signatures:

```auto
functionSignatures = [
    'supports_interface(u32)',
    'is_valid_signature(felt252,Array<felt252>)',
    ' __execute__ (Array<(ContractAddress,u32,Array<felt252>)>)',
    ' __validate__ (Array<(ContractAddress,u32,Array<felt252>)>)',
    ' __validate_declare__ (felt252)'
]

```

Being the interface id the XOR of them (similar to Solidity), that can be computed with this Python script as an example:

```auto
# pip install pysha3
import sha3

keccak_256 = sha3.keccak_256
functions = [
    'supports_interface(u32)',
    'is_valid_signature(felt252,Array<felt252>)',
    ' __execute__ (Array<(ContractAddress,u32,Array<felt252>)>)',
    ' __validate__ (Array<(ContractAddress,u32,Array<felt252>)>)',
    ' __validate_declare__ (felt252)'
]

def get_id(fn_signature):
    id = keccak_256(fn_signature.encode()).hexdigest()[0:8]
    print(fn_signature, id)
    return id

def main():
    interface_id = 0x0
    for fn in functions:
        interface_id ^= int(get_id(fn), 16)
    print(hex(interface_id))

if __name__ == ' __main__':
    main()

```

With this SNIP we would have a settled definition of how to compute interface ids for Starknet, and this will support interoperability as ERC-165 does for Ethereum.

---

<div class="post-metadata">

**Author:** ![gaetbout](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/gaetbout/32/712_2.png) [@gaetbout](https://community.starknet.io/u/gaetbout)\
**Post date:** [May 18, 2023, 7:17am UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/2 "2023-05-18T07:17:26Z")

</div>

Hey,  
Regarding [The Great Interface Migration](https://community.starknet.io/t/the-great-interface-migration/92107)  
For some time account interface should both support  
supportsInterface(felt) and supports\_interface(u32)  
Do you think that the old supportsInterface(felt) should be true only for the old interface IDs and the new one should only support the new ones that you are describing here?  
Or they should both support all of them for the time being?

---

<div class="post-metadata">

**Author:** ![sgc-code](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/sgc-code/32/71664_2.png) [@sgc-code](https://community.starknet.io/u/sgc-code)\
**Post date:** [May 18, 2023, 9:20am UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/3 "2023-05-18T09:20:28Z")

</div>

Hi Eric,

First of all, i think this is a great initiative. IMO it made no sense to try to be that close to ethereum.

If we are changing they way we calculate the interface id, would it also make sense to make interface if a full `felt252`? I don’t see the need to follow ethereum bytes4 size. I creates many collisions, some of them even accidentally. And we also use felts for methods selectors on Starknet. Also. looks like it’s compatible with the old interface in Cairo 0 which expected a felt.

On another topic. The example for the Account interface looks great, but how would it look like if we have customs Structs? I think we need to agree on a way to do those too.

---

<div class="post-metadata">

**Author:** ![ericnordelo](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/ericnordelo/32/1371_2.png) [@ericnordelo](https://community.starknet.io/u/ericnordelo)\
**Post date:** [May 18, 2023, 1:18pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/4 "2023-05-18T13:18:14Z")

</div>

> First of all, i think this is a great initiative. IMO it made no sense to try to be that close to ethereum.
> 
> If we are changing they way we calculate the interface id, would it also make sense to make interface if a full `felt252`? I don’t see the need to follow ethereum bytes4 size. I creates many collisions, some of them even accidentally. And we also use felts for methods selectors on Starknet. Also. looks like it’s compatible with the old interface in Cairo 0 which expected a felt.
> 
> On another topic. The example for the Account interface looks great, but how would it look like if we have customs Structs? I think we need to agree on a way to do those too.

Starting with the second topic, we have Call in the example being a custom struct, my idea is to follow what Solidity does with structs, decomposing them in tuples recursively. You can see the example here:

` __execute__ (Array<(ContractAddress,u32,Array<felt252>)>`

About the first topic, we could maintain u32 instead of felt252 just to keep “easier to handle” ids. Is easier to check `0xc5d24601` than this `0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470` right?

Maybe is more gas costly to handle u32 than felt252 though.

---

<div class="post-metadata">

**Author:** ![ericnordelo](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/ericnordelo/32/1371_2.png) [@ericnordelo](https://community.starknet.io/u/ericnordelo)\
**Post date:** [May 18, 2023, 1:18pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/5 "2023-05-18T13:18:16Z")

</div>

> Do you think that the old supportsInterface(felt) should be true only for the old interface IDs and the new one should only support the new ones that you are describing here?  
> Or they should both support all of them for the time being?

I think both methods should behave the same, returning true for every interface the contract supports. Keep in mind that what I’m proposing is a way of standardizing how interface ids are created, but it doesn’t enforce camelCase or snake\_case, so you can still have merged syntax and generate a valid interface id using this mechanism. The use of snake\_case is just a convention with important implications for interoperability.

With Accounts, for example, we would maintain camelCase and snake\_case, generate two ids using this standard for both interfaces, and support both numbers in both methods.

---

<div class="post-metadata">

**Author:** ![sgc-code](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/sgc-code/32/71664_2.png) [@sgc-code](https://community.starknet.io/u/sgc-code)\
**Post date:** [May 18, 2023, 7:09pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/6 "2023-05-18T19:09:49Z")

</div>

All good regarding structs then, that should work. What about Spans vs Arrays? Any idea of what to do with them? Should we consider them different?

Regarding the selectors. I see your point, you can quickly check it visually. But you can also look only at the beginning or end to achieve the same. I would still have a full felt252 because:

- It’s consistent with starknet selectors
- It’s safer, avoids collisions
- Should more performant as you don’t need to check that the first bytes are all zeros. Although it should be minimal

Just my opinion 🙂

---

<div class="post-metadata">

**Author:** ![yoga\_Braavos](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/yoga_braavos/32/858_2.png) [@yoga\_Braavos](https://community.starknet.io/u/yoga_Braavos)\
**Post date:** [May 19, 2023, 1:04pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/7 "2023-05-19T13:04:13Z")

</div>

Thanks @ericnordelo for the initiative.

I agree with going with `felt252` to save gas. Are there any substantial benefits for using `u32` that I missed?

---

<div class="post-metadata">

**Author:** ![ericnordelo](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/ericnordelo/32/1371_2.png) [@ericnordelo](https://community.starknet.io/u/ericnordelo)\
**Post date:** [May 20, 2023, 1:44am UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/8 "2023-05-20T01:44:59Z")

</div>

> What about Spans vs Arrays? Any idea of what to do with them?

Span and Array are different types (even when they represent similar things). The compiler will even start treating Span as an owned type soon, as you can see from [this PR](https://github.com/starkware-libs/cairo/pull/3189). I think we should handle them as different types accordingly.

---

<div class="post-metadata">

**Author:** ![ericnordelo](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/ericnordelo/32/1371_2.png) [@ericnordelo](https://community.starknet.io/u/ericnordelo)\
**Post date:** [May 20, 2023, 1:45am UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/9 "2023-05-20T01:45:02Z")

</div>

> Are there any substantial benefits for using `u32` that I missed?

Besides shorter (aka “easier to handle”) ids I don’t think so. I agree it could be good to maintain the consistency with selectors and save some gas using felt252. Note that function selectors can’t be used for id generation though, as they do not include parameters in Starknet, and the interface id should represent input types as well.

---

<div class="post-metadata">

**Author:** ![sgc-code](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/sgc-code/32/71664_2.png) [@sgc-code](https://community.starknet.io/u/sgc-code)\
**Post date:** [May 24, 2023, 9:20am UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/10 "2023-05-24T09:20:23Z")

</div>

I’d like to provide an updated example of how it will look like if we stick with `felt252` for selectors

This would be interface in Cairo:

```auto
struct Call {
    to: ContractAddress,
    selector: felt252,
    calldata: Array<felt252>
}

trait IAccount {
    fn supports_interface(felt252);
    fn is_valid_signature(felt252, Array<felt252>);
    fn __execute__ (Array<Call>);
    fn __validate__ (Array<Call>);
    fn __validate_declare__ (felt252);
}

```

And this is the python code that computes the interface id. Note that i updated the hash function to `starknet_keccak` instead of `keccak_256`

```auto
# pip install cairo-lang
from starkware.starknet.public.abi import starknet_keccak

functions = [
    'supports_interface(felt252)',
    'is_valid_signature(felt252,Array<felt252>)',
    ' __execute__ (Array<(ContractAddress,felt252,Array<felt252>)>)',
    ' __validate__ (Array<(ContractAddress,felt252,Array<felt252>)>)',
    ' __validate_declare__ (felt252)'
]

def main():
    interface_id = 0x0
    for function in functions:
        function_id = starknet_keccak(function.encode())
        print(f"{hex(function_id)} hash for {function}")
        interface_id ^= function_id
    print('IAccount ID:')
    print(hex(interface_id))

if __name__ == " __main__":
    main()

```

Which outputs the following ID for IAccount

```auto
0x396002e72b10861a183bd73bd37e3a27a36b685f488f45c2d3e664d0009e51c

```

Do you think it’s ok? Any feedback is appreciated

---

<div class="post-metadata">

**Author:** ![ericnordelo](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/ericnordelo/32/1371_2.png) [@ericnordelo](https://community.starknet.io/u/ericnordelo)\
**Post date:** [May 29, 2023, 11:19am UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/11 "2023-05-29T11:19:32Z")

</div>

Thanks @sgc-code , that looks good. I will work on a proper SNIP proposal based on this to continue the discussion.

---

<div class="post-metadata">

**Author:** ![ericnordelo](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/ericnordelo/32/1371_2.png) [@ericnordelo](https://community.starknet.io/u/ericnordelo)\
**Post date:** [May 30, 2023, 2:09pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/12 "2023-05-30T14:09:39Z")

</div>

Here is the SNIP Draft’s first version:

> <https://github.com/ericnordelo/SNIPs/blob/feat/standard-interface-detection/SNIPS/snip-5.md>

cc @sgc-code @yoga_Braavos

---

<div class="post-metadata">

**Author:** ![martriay](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/martriay/32/25_2.png) [@martriay](https://community.starknet.io/u/martriay)\
**Post date:** [June 2, 2023, 12:08am UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/13 "2023-06-02T00:08:21Z")

</div>

> [@sgc-code](#):
>
> - It’s consistent with starknet selectors

What do you mean by consistent? what does interface id type definition have to do with selectors?

---

<div class="post-metadata">

**Author:** ![sgc-code](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/sgc-code/32/71664_2.png) [@sgc-code](https://community.starknet.io/u/sgc-code)\
**Post date:** [June 2, 2023, 11:42am UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/14 "2023-06-02T11:42:17Z")

</div>

In ERC-165 they define the interface id as:

> the XOR of all function selectors in the interface

Since selectors are `bytes4` in EVM world, that makes the interface id a `bytes4` too.

Following the same logic, i think, the interface id should be a `felt252` in Starknet.

---

<div class="post-metadata">

**Author:** ![ericnordelo](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/ericnordelo/32/1371_2.png) [@ericnordelo](https://community.starknet.io/u/ericnordelo)\
**Post date:** [June 6, 2023, 12:26pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/15 "2023-06-06T12:26:32Z")

</div>

Here is an update on the elements we’ve been discussing in other channels (the Draft has been updated accordingly):

- Generic types have been removed from the standard because they can’t be part of the external API of a contract.
- Arguments of external functions must use a default serializer, for the contract to be SNIP-5 compliant. This supports easier interoperability, allowing calling contracts to trust that the behavior of two different targets exposing the same interface would be compatible regarding serialization. The standard for Tuples, Structs, and Enums is the same that we get from using the derive attribute which is: the concatenation of the serialized fields for Structs and Tuples, and the concatenation of a felt252 acting as a variant identifier and the serialized value for Enums.
- Types defined in corelib as external types will be treated as core types, but structs and Enums from corelib will be treated as such (ex: `u256` is represented as` (u128,u128)`).
- The interface id is the starknet\_keccak of the XOR of the Extended Function Selectors with the given signature (ASCII encoded).

---

<div class="post-metadata">

**Author:** ![ericnordelo](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/ericnordelo/32/1371_2.png) [@ericnordelo](https://community.starknet.io/u/ericnordelo)\
**Post date:** [June 8, 2023, 12:47pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/16 "2023-06-08T12:47:17Z")

</div>

Also, in ERC-165, a part of the specification is that the `supports_interface` method must return `false` for the interface `0xffffffff`. As far as I understand, this was included for backward compatibility, to determine that contracts previous to this standard don’t implement the interface. This is not included in the SNIP because it seems unnecessary for the current Starknet state.

---

<div class="post-metadata">

**Author:** ![gaetbout](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/gaetbout/32/712_2.png) [@gaetbout](https://community.starknet.io/u/gaetbout)\
**Post date:** [June 15, 2023, 10:19am UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/17 "2023-06-15T10:19:12Z")

</div>

With the latest changes about [the syntax evolving](https://community.starknet.io/t/cairo-1-contract-syntax-is-evolving/94794)  
Do you think it is useful to add self in the computation?

---

<div class="post-metadata">

**Author:** ![ericnordelo](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/ericnordelo/32/1371_2.png) [@ericnordelo](https://community.starknet.io/u/ericnordelo)\
**Post date:** [June 15, 2023, 12:24pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/18 "2023-06-15T12:24:58Z")

</div>

In my opinion, yes. From the fact that `self` type is not always the same (`@ContractState` or `ref ContractState`), I think it should be part of the signature as any other parameter. Having represented in the signature whether the function can modify the storage or not, looks like a nice extra feature to me. Interested in others’ thoughts.

---

<div class="post-metadata">

**Author:** ![gaetbout](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/gaetbout/32/712_2.png) [@gaetbout](https://community.starknet.io/u/gaetbout)\
**Post date:** [June 15, 2023, 12:37pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/19 "2023-06-15T12:37:54Z")

</div>

Shahar also mentioned that the Account interface could be updated to something that looks like:

```plaintext
trait Account<State, TxInp, TxOut> {
  fn __validate__ (ref self: State, inp: TxInp) -> bool;
  fn __execute__ (ref self: State, inp: TxInp) -> TxOut;
}

```

I guess this would also have an impact and needs to be agreed on.

---

<div class="post-metadata">

**Author:** ![ericnordelo](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/ericnordelo/32/1371_2.png) [@ericnordelo](https://community.starknet.io/u/ericnordelo)\
**Post date:** [June 15, 2023, 1:52pm UTC](https://community.starknet.io/t/starknet-standard-interface-detection/92664/20 "2023-06-15T13:52:50Z")

</div>

> [@gaetbout](#):
>
> ```auto
> trait Account<State, TxInp, TxOut> {
> fn __validate__ (ref self: State, inp: TxInp) -> bool;
> fn __execute__ (ref self: State, inp: TxInp) -> TxOut;
> }
> 
> ```

This is interesting, I actually removed the Generics section of the SNIP-5 after some discussion, because generic types weren’t allowed in external functions for smart contracts. I think this behavior remains, so this generic Account trait would not actually be representing the interface, but a blueprint of interfaces that will be defined after implementing the trait with specific types.

Not sure if we want to allow an interface (for SNIP-5 interoperability) with these generic types.

[Next page](https://community.starknet.io/t/starknet-standard-interface-detection/92664.md?page=2)
