Skip to main content

Multi-Party Contract Tutorial

Create a contract where only Alice or Bob can make commits.

Step 1: Create Identities

Create named identities (stored automatically in ~/.modality/):

modal id create --name alice
modal id create --name bob

This creates:

  • ~/.modality/alice.mod_passfile
  • ~/.modality/bob.mod_passfile
tip

Named passfiles are stored in ~/.modality/ by default — never in the contract directory!

Step 2: Create Contract

mkdir my-contract && cd my-contract

# Create the contract
modal contract create

# Initialize directories
modal c checkout

Step 3: Set Up Users

# Add user IDs using named passfiles
modal c set-named-id /users/alice.id --named alice
modal c set-named-id /users/bob.id --named bob

Step 4: Define the Rules

Create rules/auth.modality — the authorization rule:

export default rule {
starting_at $PARENT
formula {
signed_by(/users/alice.id) | signed_by(/users/bob.id)
}
}

This rule requires every commit to be signed by either Alice or Bob.

Step 5: Synthesize the Model

Generate a model that satisfies the rules:

modality model synthesize --rule rules/auth.modality -o model/default.modality

Or view the synthesized model first:

modality model synthesize --rule rules/auth.modality

The synthesizer generates a labeled transition system where all transitions require the appropriate signatures.

Step 6: Commit the Setup (Signed)

modal c commit --all --sign alice

From this point on, all commits must be signed by Alice or Bob.

Step 7: Make Signed Changes

# Alice posts a message
mkdir -p state/data
echo "Hello from Alice" > state/data/message.text
modal c commit --all --sign alice

# Bob updates the message
echo "Hello from Bob" > state/data/message.text
modal c commit --all --sign bob

Step 8: View Status & Log

modal c status
modal c log

Directory Structure

Your contract directory contains only public data:

my-contract/
├── .contract/ # Internal storage
├── state/ # Data files
│ ├── users/
│ │ ├── alice.id # Public key only
│ │ └── bob.id # Public key only
│ └── data/
│ └── message.text
├── rules/ # Rules first
│ └── auth.modality
└── model/ # Synthesized model
└── default.modality

Private keys stay in your home directory:

~/.modality/
├── alice.mod_passfile # Private key (never share!)
└── bob.mod_passfile # Private key (never share!)