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!)