---
# System prepended metadata

title: '(Draft) L1-Embedding for EVM like blockchains:'
tags: [EVM, Ethereum]

---

# (Draft) L1-Embedding for EVM like blockchains:


### Context:

On EVM like blockchains, transactions carry a field named **calldata** containing a raw bytestring. When a transaction is sent to an smartcontract, the **calldata** field becomes the input to the smartcontract's code. When sent to the special _"create_contract"_ address, the field will represent the smart contract to be created. Otherwise, when sent to any other type of address the field will be ignored, leaving us free to use it for any other mean; furthermore the restrictions, in this case, for the field content and size limit are very loose. **This makes it trivial to embed data**, _just as it is_, on the **calldata** field.

On the other hand, as EVM blockchain can be programmed with custom logic (i.e smartcontracts), it is interesting to enable some (limited) l2->l1 interaction (as opposed to l1->l2). We could achive this adding some restriction on how to embed data, so the l1-logic could make some assumptions.


Notice that, on EVM like blockchains, there's the notion of transactions having succeed or failed; in either case, the transaction will be mined and hence its content avaliable to the l2-layer logic, but failed transaction will be invisible to l1-layer logic. Also, as a pragmatic consideration, most information regarding failed transactions, such which events triggered, will not be indexed by most tools and services. 

### Proposal:

The goals are: 

- make the embedded data avaliable for both, l1 and l2 logic, so developers can find better ways to relate both universes. 

- l2 embedded data can not be hidden from l1 logic.

- Allow a tight low-redundant representation for those cases where we only care about l2 layer. 

- Allow a convenient, solidity-compatible, representation that evm developers can use without requiring any new tool.

- Leave room for a future, to be determined, intermidiate representation(s), compatible with smartcontracts but taking advantage of custom tools.

For that, we'll differentiate between the following cases:

- **Calldata contains a reserved string of bytes**: This case will be imposible, because in the future, once we need a new label, we will pick one such it hasn't been used before; so it won't break anything.

- Calldata does not contains a reserved string of bytes, and **contains the `l2_msg` string of bytes**: We'll take the _calldata_ substring from right after the last occurence of `l2_msg`, till the end of the calldata field, and call it `raw_l2_msg`, then:

  - If the l1-transaction carring this payload failed, then we skip and do not yield any l2-transaction.

  - If the l1-transaction carring this payload succeed, we'll return `raw_l2_msg` to the l2-layer, but, instead of using the standard _l2_transaction parser_, we'll use the special _l2_from_solidity_transaction_ parser (explained on the appendix).
     

- It does not contain neither type of string of bytes: We'll take the whole `calldata` and pass it to the _l2_transaction parser_.

#### Rationale:

Most EVM smartcontracts, if not all, follow the solidity [ABI interface](https://docs.soliditylang.org/en/v0.8.4/abi-spec.html). This is not a self documented interface, so it is not possible to recover the arguments without some metadata that is hard to keep up to date without compiler/tooling support. This complicates reading the same l2-transaction by both, l1 and l2 logic. But if we add a mark (the `l2_msg` bytestring) and assume that the l2-transaction contains that mark as its first field, and is the last smartcontract method argument, then we'll know that its abi-encoded byte string representation would be the calldata sub bytestring that goes from `l2_msg` till the end.


Then we could get something that on l1-layer logic would look like this:

```
// Using coinweb-sol library

contract Example{

    function example( arg1 a1, arg2 a2, ... argN aN
                    , L2RawTransaction calldata raw_l2tx 
                    ) external {
    
      
      L2Transaction l2tx = parseVerify(raw_l2tx)
    
      ...
      ...
    
    }

}

```

```
// library:

struct L2RawTransaction{
  bytes mark;
  ... other fields...
}

function parseVerify(L2RawTransaction calldata raw_l2tx) pure L2Transaction{
      require( raw_l2tx.mark = 0xe2650a7db15c8c7d7ac3a490d0791b521c4ff31be19b689c373f65f53d374788
             , 'mark didn't match 
             );
      
      ...

}
```

Then if we assume that the l2-level logic would check that the inconming l2-transaction was embedded from a call to `Example.exmple`, then we have a way to make l1 and l2 logic to see the same set of l2-transactions.


#### Pros:
- ...
#### Cons:
- ... 

### Tasks:

#### A:

**For the very first version**, we'll just take calldata as it is.

#### B:

Then implement the _l2_from_solidity_transaction_ and take into consideration whether calldata contains or not `l2_msg`.

#### C:

Write solidity library (partially programatically-generated?) to use and write some simple l1/l2 interaction examples.

#### D:

Pass transaction context a long side the parse transaction.


### Future & EIP-2224:

### Appendix:

#### Labels: 
- `l2_msg`: `0xe2650a7db15c8c7d7ac3a490d0791b521c4ff31be19b689c373f65f53d374788` (32 arbitrarily choosen bytes). Notice that standard solidity ABI words are 32 bytes width.

- Reserved string of bytes: A list to  of bytestrings (with might habe different width) that will be eventually determined when need. 


#### Solidity ABI representation & decoding: 

#### Solidity interaction:


###### tags: `EVM` `Ethereum`

