A TypeScript-based workflow simulation runner that fetches workflow metadata from IPFS, validates triggers, simulates with Kernel SDK, and (optionally) executes on supported chains.
- Strict‐mode TypeScript throughout (no implicit
any) - Zod-validated runtime configuration via environment variables
- Modular architecture:
db,eventMonitor,worker,parsers, and SDK integration - Structured logging via Winston
- ESLint + Prettier code style enforcement
- GitHub Actions CI: install → lint → compile
| Tool | Version |
|---|---|
| Node | 20.x |
| npm | 10.x |
| MongoDB | >=6.0 (local or remote) |
| IPFS Gateway | accessible HTTP endpoint |
# clone & install
git clone <repo>
cd simulator
npm install
git submodule update --init --recursive
npm run build -w ditto-workflow-sdk
# copy and adjust environment variables
cp .env.example .env
# compile
npm install
npm run build
# run the simulator (dev)
npm run devSee env.example for the full list. Key values:
MONGO_URI=mongodb://localhost:27017
DB_NAME=indexer
RPC_URL=https://rpc.ankr.com/eth_sepolia
EXECUTOR_PRIVATE_KEY=0x...
EXECUTOR_ADDRESS=0x...
AGGREGATOR_URL=http://localhost:8080
OTHENTIC_FLOW=false
FULL_NODE=false
MAX_WORKERS=4
RUNNER_NODE_SLEEP=60All variables are validated at runtime in src/config.ts.
| Command | Purpose |
|---|---|
npm run dev |
Start simulator using tsx (ts-node equivalent) |
npm run build |
Transpile TypeScript → dist/ |
npm run lint |
ESLint check (--max-warnings=0) |
npm run lint:fix |
Auto-fix ESLint issues |
npm run format |
Prettier write |
npm run test:integration |
Minimal integration smoke test |
Logs are emitted to stdout using Winston with timestamp & colorized level. Module-specific child loggers are created via getLogger('Module').
Every push & pull-request triggers the GitHub Actions workflow located at .github/workflows/ci.yml which:
- Checks out the repo
- Sets up Node 20 with npm cache
- Installs dependencies via
npm ci - Runs
npm run lint - Runs
npm run build
- Fork & branch from
initial-impl - Follow Prettier/Lint rules (
npm run lint:fix) - Submit a PR; CI must pass
MIT © 2025
- Node.js 18+
- Git
- Docker (optional)
-
Clone this repository:
git clone <simulator-repo-url> cd simulator
-
Run the setup script:
./setup.sh
This will:
- Clone the WorkflowSDK into
./ditto-workflow-sdk/ - Build the SDK
- Install simulator dependencies
- Build the simulator
- Clone the WorkflowSDK into
-
Configure environment:
cp env.example .env # Edit .env with your configuration
simulator/
├── ditto-workflow-sdk/ # SDK cloned here (auto-generated)
├── src/
│ ├── integrations/
│ │ ├── workflowSDK.ts # TypeScript integration bridge
│ │ └── workflowSDK.js # JavaScript wrapper
│ ├── index.js # Main simulator
│ ├── worker.js # Workflow processor
│ └── test-integration.js # Integration tests
├── Dockerfile # Production Docker image
├── Dockerfile.test # Test Docker image
├── setup.sh # Setup script
└── package.json
Run integration tests:
npm run test:integrationHTTP server exposes a validation endpoint used to pre-approve workflow executions by simulating them via the Workflow SDK.
- Base URL:
http://localhost:${HTTP_PORT}(default8080) - Endpoint:
POST /task/validate
Request body (JSON):
{
"proofOfTask": "<ipfsHash_nextSimulationTime_chainId>",
"data": "<encoded callData string>",
"taskDefinitionID": 123,
"performer": "0x1234abcd5678ef901234abcd5678ef901234abcd",
"targetChainId": 11155111
}Constraints:
proofOfTask: required string, formatipfsHash_nextSimulationTime_chainIDdata: required non-empty string (encoded tuple(address,uint256,bytes,bytes,bytes32,uint256,bytes32,bytes,bytes)containing packed user operation data)taskDefinitionID: uint16 (0…65535)performer: EVM address (0x+ 40 hex chars)targetChainId: uint16 (chain to compare results against)
Response (200):
{ "data": true | false, "error": false, "message": null | string }data=truemeans the simulation succeeded and the produced callData exactly matchesdatafor the specifiedtargetChainId.- On validation errors (bad input) the API returns 200 with
error=trueand a descriptivemessage. - On unexpected exceptions the API returns 500 with
error=true.
Example:
curl -sS -X POST http://localhost:8080/task/validate \
-H 'Content-Type: application/json' \
-d '{
"proofOfTask": "Qm...",
"data": "0xabcdef...",
"taskDefinitionID": 1,
"performer": "0x1234abcd5678ef901234abcd5678ef901234abcd",
"targetChainId": 11155111
}'npm start# Build image
docker build -t simulator .
# Run container
docker run --env-file .env simulatordocker-compose upRequired environment variables:
# MongoDB
MONGO_URI=mongodb://localhost:27017
DB_NAME=indexer
# Blockchain
RPC_URL=https://your-rpc-url
EXECUTOR_PRIVATE_KEY=0x...
WORKFLOW_CONTRACT_ADDRESS=0x...
IPFS_SERVICE_URL=https://your-ipfs-service
# Simulator Settings
RUNNER_NODE_SLEEP=6
MAX_WORKERS=2
FULL_NODE=trueAdditional variables used by the API and runtime:
# HTTP server
HTTP_PORT=8080
# When enabled, runs only the HTTP API (no simulator loop)
API_ONLY=true
# ZeroDev & environment for simulation
IPFS_SERVICE_URL=your-zerodev-api-key
IS_PROD=false
# Per-chain RPC (overrides); falls back to SDK chain config
# RPC_URL_<CHAIN_ID>=https://...When OTHENTIC_FLOW=true, execution switches to an aggregator JSON-RPC call with ECDSA signing of a message hash built as:
keccak256(abi.encode(string proofOfTask, bytes data, address performer, uint16 taskDefinitionId))
The simulator sends to AGGREGATOR_URL:
{
"jsonrpc": "2.0",
"method": "sendTask",
"params": [
"<proofOfTask>",
"<data>",
"<taskDefinitionId>",
"<performerAddress>",
"<signature>",
"ecdsa",
"<targetChainId>"
]
}proofOfTask:ipfsHash_nextSimulationTime_chainIDdata: encoded tuple containing packed user operation dataperformerAddress: fromEXECUTOR_ADDRESSsignature: produced usingEXECUTOR_PRIVATE_KEYtargetChainId: from simulation result
To update the WorkflowSDK to the latest version:
./setup.shFor Docker development with live updates:
# Build test image
docker build -f Dockerfile.test -t simulator-test .
# Run integration test
docker run --env-file .env simulator-testThe simulator:
- Connects to MongoDB to find workflows ready for execution
- Loads workflow data from IPFS using the WorkflowSDK
- Simulates execution to estimate gas costs
- Executes workflows on-chain using ZeroDev sessions
- Updates MongoDB with execution results and next run times
- ✅ Real blockchain execution using ZeroDev Account Abstraction
- ✅ Data-driven approach with workflow dictionaries
- ✅ MongoDB integration for workflow storage and caching
- ✅ Docker support for production deployment
- ✅ TypeScript integration with proper type safety
- ✅ Automatic scheduling with cron trigger support
- ✅ Gas estimation before execution
- ✅ Error handling and retry logic
npm run buildnpm run build:watchIf you're developing the SDK locally, the simulator will automatically use your local changes after running ./setup.sh.