CELLS

2/2 MULTISIG PROTOCOL
SCROLL ↓
0

Introduction

Cell Wallet is an opinionated 2-of-2 multisig smart contract wallet on Ethereum, with an optional soft guardian role for 2-of-3 recovery. It's designed for simplicity, security, and sovereignty.

The Cells protocol is deployed at 0x000000000022Edf13B917B80B4c0B52fab2eC902

A lite version (minimal proxy factory) is deployed at 0x000000000022fe09b19508Ceeb97FBEb41B66d0F

Access the dApp at cellwall.eth.limo

1

Core Concepts

2/2 Multisig

Every Cell requires exactly two owners to approve any transaction. This provides maximum security without the complexity of threshold signatures. Both owners have equal power—no hierarchy, no single point of failure.

Sorted Ownership

Owners are automatically sorted by address (owner0 < owner1). This ensures deterministic behavior and prevents ordering confusion.

Guardian Role

An optional third signer with limited powers. The guardian can initiate and co-approve transactions but cannot directly set allowances or permits—those require 2/2 owner consensus. Perfect for recovery scenarios or trusted third-party assistance.

2

Key Features

Chat Messages
On-chain communication between owners. Discuss transactions, leave notes, coordinate approvals.
Allowances
Grant spending permissions to the other owner. No 2/2 needed for pre-approved amounts.
Permits
Issue reusable execution permits. Allow repeated actions without constant re-approval.
Batch Execute
Process multiple transactions atomically. All succeed or all revert together.
EIP-712 Signing
Sign transactions offline. Approve via signature without being online simultaneously.
Ownership Transfer
Transfer your ownership slot to another address. Maintains sorted order automatically.
3

Technical Details

Contract Architecture

// Core state variables address[3] public owners; // [owner0, owner1, guardian] string[] public messages; // On-chain chat mapping(bytes32 => address) public approved; // Pending approvals mapping(address => mapping(address => uint256)) public allowance;

Transaction Flow

  1. Initiate: First owner calls execute() with transaction details
  2. Hash: Transaction is hashed and stored with first approver
  3. Approve: Second owner calls execute() with same parameters
  4. Execute: Transaction executes atomically upon second approval

Hashing Mechanism

Transactions are identified by their content hash:

bytes32 hash = keccak256(abi.encodePacked( this.execute.selector, to, value, keccak256(data), nonce ));
4

Special Permissions

Action Owner 0/1 Guardian
Initiate transaction
Approve & execute
Send chat message
Transfer ownership
Set allowances
Cancel pending ✓ (if approver) ✓ (if approver)
5

Using the dApp

Getting Started

  1. Visit cellwall.eth.limo
  2. Connect your Web3 wallet (Rainbow, MetaMask, Coinbase)
  3. Create new Cell or access existing ones

Interface Elements

Black Half (Owner 0)

Left side shows Owner 0 address, status, and pending count

White Half (Owner 1)

Right side shows Owner 1 address, status, and pending count

Chat Drawer

Bottom drawer for messages, transactions, allowances, and permits

Transaction Types

6

Security Considerations

Best Practices

Recovery Scenarios

Lost one owner key: Remaining owner + guardian can execute ownership transfer to new address.

Lost guardian key: Both owners can update guardian address.

Lost both owner keys: Funds are permanently locked. Always maintain secure backups.

7

Gas Optimization

Cell uses several gas optimization techniques:

// Optimized reentrancy guard using transient storage modifier nonReentrant() { assembly { if tload(REENTRANCY_GUARD_SLOT) { mstore(0x00, 0xab143c06) revert(0x1c, 0x04) } tstore(REENTRANCY_GUARD_SLOT, address()) } _; assembly { tstore(REENTRANCY_GUARD_SLOT, 0) } }
8

Examples

Creating a Cell

// Via Cells contract cells.createCell( owner0, // First owner (will be sorted) owner1, // Second owner guardian, // Optional guardian (or address(0)) salt, // Random salt for CREATE2 initCalls // Initial setup calls );

Executing a Transaction

// First approval cell.execute( to, // Target address value, // ETH amount data, // Call data nonce // Unique nonce ); // Second approval (same parameters) cell.execute(to, value, data, nonce); // Transaction executes automatically

Setting Allowance

// Allow other owner to spend 10 USDC cell.setAllowance( address(0), // Spender (0 = other owner) USDC_ADDRESS, // Token address 10e6 // Amount (with decimals) );
9

Advanced Features

Multicall

Execute multiple calls to the Cell contract atomically:

bytes[] memory calls = new bytes[](2); calls[0] = abi.encodeCall(cell.chat, "Sending funds"); calls[1] = abi.encodeCall(cell.execute, (to, value, data, nonce)); cell.multicall(calls);

Delegate Execution

Execute code in Cell's context (for upgrades/modules):

cell.delegateExecute( implementationContract, delegateCallData, nonce );

EIP-712 Signatures

Approve transactions offline via structured signatures:

cell.batchExecuteWithSig( tos, // Target addresses array values, // Values array datas, // Call data array nonce, // Batch nonce deadline, // Expiry timestamp v, r, s // Signature components );