# Signing transactions and off-chain messages

**URL:** <https://community.starknet.io/t/signing-transactions-and-off-chain-messages/66>\
**Category:** Starknet Technical Development\
**Created:** [November 25, 2021, 10:50am UTC](https://community.starknet.io/t/signing-transactions-and-off-chain-messages/66 "2021-11-25T10:50:33Z")\
**Posts on this page:** 1\
**Showing post:** 3

<div class="post-metadata">

**Author:** ![juniset](https://dub1.discourse-cdn.com/flex005/user_avatar/community.starknet.io/juniset/32/40_2.png) [@juniset](https://community.starknet.io/u/juniset)\
**Post date:** [February 7, 2022, 11:18am UTC](https://community.starknet.io/t/signing-transactions-and-off-chain-messages/66/3 "2022-02-07T11:18:17Z")

</div>

_Since several people have asked us if Argent X is supporting EIP-712 I guess this thread does not have the visibility that it should_ 🙂

_I’m thus posting here the content of the Github discussion linked above which is a proposal for a version of EIP-712 adapted to StarkNet._

_Note that this is already implemented in `starknet.js` and Argent X._

## Context

Wallets have to generate signatures for 2 different types of data: transactions that will be sent to an Account Contract (AC) via the sequencer, and off-chain messages that will be returned to the requesting dapp for verification by calling the `is_valid_signature` method on the AC.

It is essential that there is no collision between the two sets of signatures, or, in other words, we must ensure that a signature generated on the encoded data of an off-chain message can never be a valid signature on the encoded data of a transaction.

In Ethereum the encoded data of a transaction is clearly defined as `RLP<nonce, gasPrice, startGas, to, value, data>` and one can easily satisfy the no-collision requirement by starting the encoded data of an off-chain message by `0x19` since it can never be the first byte of RLP encoded data. This is specified in [EIP-191](https://eips.ethereum.org/EIPS/eip-191).

In addition, a good encoding scheme should make it easy for the wallet to clearly display to the user what he is signing. In Ethereum, this is specified in [EIP-712](https://eips.ethereum.org/EIPS/eip-712).

On Starknet we have Account Abstraction, which means that the data to be signed for a transaction is (at least for now) completely open.

## Proposition

We define the 2 short string prefixes:

- PREFIX\_TRANSACTION = `'StarkNet Transaction'`
- PREFIX\_MESSAGE = `'StarkNet Message'`

and the encoding:

> Enc[X=(x0, x1, …, xn-1)] = Enc[Enc[x0], Enc[x1], …, Enc[xn-1]] = h(…h(h(0,Enc[x0]), Enc[x1]), …), n)

when X is an array, and:

> Enc = x

when x is a felt, where

> h(a,b)

is the Pedersen hash on 2 field elements.

We also define

> selector(str) = starknet\_keccak(str)

as defined in [https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/starknet/public/abi.py](https://github.com/starkware-libs/cairo-lang/blob/master/src/starkware/starknet/public/abi.py)

### Transaction

As part of the discussions around the Account Contract interface, it was decided that AC will expose a single entry point for the execution of transactions:

```auto
@external
func execute(
        to: felt,
        selector: felt,
        calldata_len: felt,
        calldata: felt*,
        nonce: felt
    ) -> (response : felt):
end

```

For the moment there exists 2 implementations of Account Contracts:

- Account.sol in [GitHub - OpenZeppelin/cairo-contracts: OpenZeppelin Contracts written in Cairo for Starknet, a decentralized ZK Rollup](https://github.com/OpenZeppelin/cairo-contracts)
- ArgentAccount.sol in [GitHub - argentlabs/argent-contracts-starknet: Argent accounts for Starknet](https://github.com/argentlabs/argent-contracts-starknet)

Based on the above, the data to sign for a transaction from an AC calling the function `method(params1, params2, ..., paramsN)` on the contract `to` can be defined as:

> signed\_data = Enc[PREFIX\_TRANSACTION, account, to, selector(‘method’), Enc[[params1, params2, …, paramsN]], nonce]

### Off-chain message

Inspired by EIP-712 we can define the encoding of an off-chain message as:

> signed\_data = Enc[PREFIX\_MESSAGE, domain\_separator, account, hash\_struct(message)]

where

- `domain_separator` is defined below.
- `account` is the Account Contract for which the signing is executed
- ` hash_struct(message)` is defined below.

**hash\_struct:**

The message to be hashed is represented as a struct:

```auto
struct MyStruct:
    member param1: felt
    member param2: felt*
   ...
end

```

and we define its encoding as

> hash\_struct(message) = Enc[type\_hash(MyStruct), Enc[param1], Enc[param2], …, Enc[paramN]]

where `type_hash` is defined as in EIP-712 (but using `selector` instead of `keccak`):

> type\_hash(MyStruct) = selector(‘MyStruct(params1:felt, params2:felt\*,…)’)

If MyStruct references other struct types (and these in turn reference even more struct types), then the set of referenced struct types is collected, sorted by name and appended to the encoding. See [EIP-712](https://eips.ethereum.org/EIPS/eip-712) for more details

**domain\_separator:**

The `domain_separator` is defined as the `hash_struct` of the `StarkNetDomain` struct:

```auto
struct StarkNetDomain:
    member name: felt = 'www.myDapp.com'
    member version: felt = 1
    member chain_id: felt = 'SN_GOERLI'
end

```

where `chain_id` is one of `['SN_GOERLI', 'SN_MAIN']` in short strings.

**Reference implementation**

- In Cairo: [https://github.com/argentlabs/argent-contracts-starknet/blob/main/contracts/StructHash.cairo](https://github.com/argentlabs/argent-contracts-starknet/blob/main/contracts/StructHash.cairo)
- in Js: [https://github.com/seanjameshan/starknet.js/pull/87](https://github.com/seanjameshan/starknet.js/pull/87)

### Some rationale elements

- The 2 prefixes `PREFIX_TRANSACTION` and `PREFIX_MESSAGE` ensure that there will be no collisions between signatures for transactions and off-chain messages.
- The `domain_separator` in the signed data of off-chain messages ensures that the signatures requested by a dapp cannot be used on another dapp, or on the same dapp but on another deployment (e.g. from Goërli to mainnet).
- The `account` in the signed data of off-chain messages ensures that if several Account Contracts use the same key, the signature requested by a dapp for an account cannot be used to authenticate another account.

---

_[View the full topic](https://community.starknet.io/t/signing-transactions-and-off-chain-messages/66)._
