---
eip: 5018
title: Filesystem-like Interface for Contracts
description: An interface to provide access to binary objects similar to filesystems.
author: Qi Zhou (@qizhou)
discussions-to: https://ethereum-magicians.org/t/eip-5018-directory-standard/8958
status: Review
type: Standards Track
category: ERC
created: 2022-04-18
---


## Abstract

The following standardizes an API for directories and files within smart contracts, similar to traditional filesystems.
This standard provides basic functionality to read/write binary objects of any size, as well as allow reading/writing chunks of the object if the object is too large to fit in a single transaction.

## Motivation

A standard interface allows any binary objects on EVM-based blockchain to be re-used by other dApps.

With [EIP-4804](./eip-4804.md), we are able to locate a Web3 resource on blockchain using HTTP-style URIs. One application of Web3 resources are web contents that are referenced within a directory using relative paths such as HTML/SVG. This standard proposes a contract-based directory to simplify the mapping between local web contents and on-chain web contents. Further, with relative paths referenced in the web contents and EIP-4804, the users will have a consistent view of the web contents locally and on-chain.

## Specification

### Directory

#### Methods

##### write

Writes binary `data` to the file `name` in the directory by an account with write permission.

```
function write(bytes memory name, bytes memory data) external payable
```

##### read

Returns the binary `data` from the file `name` in the directory and existence of the file.

```
function read(bytes memory name) external view returns (bytes memory data, bool exist)
```

##### fallback read

Returns the binary `data` from the file `prefixedName` (prefixed with `/`) in the directory.

```
fallback(bytes calldata prefixedName) external returns (bytes memory data) 
```

##### size

Returns the size of the `data` from the file `name` in the directory and the number of chunks of the data.

```
function size(bytes memory name) external view returns (uint256 size, uint256 chunks)
```

##### remove

Removes the file `name` in the directory and returns the number of chunks removed (0 means the file does not exist) by an account with write permission.

```
function remove(bytes memory name) external returns (uint256 numOfChunksRemoved)
```

##### countChunks

Returns the number of chunks of the file `name`.

```
function countChunks(bytes memory name) external view returns (uint256 numOfChunks);
```

##### writeChunk

Writes a chunk of data to the file by an account with write permission. The write will fail if `chunkId > numOfChunks`, i.e., the write must append the file or replace the existing chunk.

```
 function writeChunk(bytes memory name, uint256 chunkId, bytes memory chunkData) external payable;
```

##### readChunk

Returns the chunk data of the file `name` and the existence of the chunk.

```
function readChunk(bytes memory name, uint256 chunkId) external view returns (bytes memory chunkData, bool exist);
```

##### chunkSize

Returns the size of a chunk of the file `name` and the existence of the chunk.

```
function chunkSize(bytes memory name, uint256 chunkId) external view returns (uint256 chunkSize, bool exist);
```

##### removeChunk

Removes a chunk of the file `name` and returns `false` if such chunk does not exist. The method should be called by an account with write permission.

```
function removeChunk(bytes memory name, uint256 chunkId) external returns (bool exist);
```

##### truncate

Removes the chunks of the file `name` in the directory from the given `chunkId` and returns the number of chunks removed by an account with write permission. When `chunkId = 0`, the method is essentially the same as `remove()`.

```
function truncate(bytes memory name, uint256 chunkId) external returns (uint256 numOfChunksRemoved);
```

##### getChunkHash

Returns the hash value of the chunk data.

```
function getChunkHash(bytes memory name, uint256 chunkId) external view returns (bytes32);
```

## Rationale

One issue of uploading the web contents to the blockchain is that the web contents may be too large to fit into a single transaction. As a result, the standard provides chunk-based operations so that uploading a content can be split into several transactions. Meanwhile, the read operation can be done in a single transaction, i.e., with a single Web3 URL defined in EIP-4804.

### Interactions Between Unchunked/Chunked Functions

`read` method should return the concatenated chunked data written by `writeChunk` method. The following gives some examples of the interactions:

- `read("hello.txt")` => "" (file is empty)
- `writeChunk("hello.txt", 0, "abc")` will succeed
- `read("hello.txt")` => "abc"
- `writeChunk("hello.txt", 1, "efg")` will succeed
- `read("hello.txt")` => "abcefg"
- `writeChunk("hello.txt", 0, "aaa")` will succeed (replace chunk 0's data)
- `read("hello.txt")` => "aaaefg"
- `writeChunk("hello.txt", 3, "hij")` will fail because the operation is not replacement or append.

With `writeChunk` method, we allow writing a file with external data that exceeds the current calldata limit (e.g., 1.8MB now), and it is able to read the whole file in a single `read` method (which is friendly for large web objects such as HTML/SVG/PNG/JPG, etc).

For `write` method, calling a `write` method will replace all data chunks of the file with `write` method data, and one implementation can be:

1. `writeChunk(filename, chunkId=0, data_from_write)` to chunk 0 with the same `write` method data; and
2. `truncate(filename, chunkId=1)`, which will remove the rest chunks.

## Backwards Compatibility

No backwards compatibility issues were identified.

## Security Considerations

No security considerations were found.

## Copyright

Copyright and related rights waived via [CC0](../LICENSE.md).
