Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cspell-config/cspell-packages.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
hexlify
viem
wagmi
siwe
cbor
levischuck
ofetch
Expand Down
2 changes: 1 addition & 1 deletion examples/demo-app/scripts/deploy-msa-anvil.sh
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,14 @@ fi

echo ""
echo "✅ Deployment complete!"
echo " MockPaymaster: $PAYMASTER"
echo " EOAKeyValidator: $EOA_VALIDATOR"
echo " SessionKeyValidator: $SESSION_VALIDATOR"
echo " WebAuthnValidator: $WEBAUTHN_VALIDATOR"
echo " GuardianExecutor: $GUARDIAN_EXECUTOR"
echo " ModularSmartAccount impl: $ACCOUNT_IMPL"
echo " UpgradeableBeacon: $BEACON"
echo " MSAFactory: $FACTORY"
echo " MockPaymaster: $PAYMASTER"

# Create contracts-anvil.json
echo ""
Expand Down
14 changes: 13 additions & 1 deletion packages/auth-server-api/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@ DEPLOYER_PRIVATE_KEY=0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf

# Blockchain Configuration
RPC_URL=http://127.0.0.1:8545
BUNDLER_URL=http://127.0.0.1:4337

# Rate Limiting Configuration
RATE_LIMIT_DEPLOY_MAX=20
RATE_LIMIT_DEPLOY_WINDOW_MS=3600000 # 1 hour

# Contract Addresses (OPTIONAL - will fall back to src/contracts.json if not provided)
# You can provide these via environment variables OR update src/contracts.json
Expand All @@ -19,3 +22,12 @@ BUNDLER_URL=http://127.0.0.1:4337
# EOA_VALIDATOR_ADDRESS=0x...
# WEBAUTHN_VALIDATOR_ADDRESS=0x...
# SESSION_VALIDATOR_ADDRESS=0x...

# Prividium Mode Configuration (OPTIONAL)
# When enabled, requires user authentication via Prividium and routes deployments through Prividium RPC proxy
# PRIVIDIUM_MODE=true
# PRIVIDIUM_RPC_PROXY_BASE_URL=https://rpc.prividium.io
# PRIVIDIUM_PERMISSIONS_BASE_URL=https://permissions.prividium.io
# PRIVIDIUM_ADMIN_PRIVATE_KEY=0x... # Private key of a user with 'admin' role in Prividium
# PRIVIDIUM_TEMPLATE_KEY=sso-smart-account # Template key for whitelisting deployed contracts
# SSO_AUTH_SERVER_BASE_URL=https://sso.example.com # Base URL of the SSO auth server frontend (used as SIWE domain for admin authorization)
43 changes: 43 additions & 0 deletions packages/auth-server-api/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,46 @@ API responsible for deploying SSO smart accounts.
- `POST /api/deploy-account` - Deploy a new smart account with passkey
authentication
- `GET /api/health` - Health check endpoint

## Prividium Mode Setup

When Prividium mode is enabled, the auth server requires user authentication via
Prividium and routes all deployments through the Prividium RPC proxy.

### Configuration

Set the following environment variables to enable Prividium mode:

```env
PRIVIDIUM_MODE=true
PRIVIDIUM_RPC_PROXY_BASE_URL=https://rpc.prividium.io
PRIVIDIUM_PERMISSIONS_BASE_URL=https://permissions.prividium.io
PRIVIDIUM_ADMIN_PRIVATE_KEY=0x... # Private key of a user with 'admin' role in Prividium
PRIVIDIUM_TEMPLATE_KEY=sso-smart-account # Template key for whitelisting deployed contracts
SSO_AUTH_SERVER_BASE_URL=https://sso.example.com # Base URL of the SSO auth server frontend (used as SIWE domain for admin authorization)
```

### Prividium Admin Panel Setup

1. Create a **Contract Permission Template** in the Prividium admin panel with
the key `sso-smart-account` (or the value you set for
`PRIVIDIUM_TEMPLATE_KEY`)
2. Configure the template with the required permissions listed below

### Contract ABI

The SSO smart account contract ABI is available at:
[`packages/erc4337-contracts/out/ModularSmartAccount.sol/ModularSmartAccount.json`](../erc4337-contracts/out/ModularSmartAccount.sol/ModularSmartAccount.json)
after compiling the contracts.

### Required Permissions

Configure the following method permissions in your contract template:

| Function | Permission Level | Access Details |
| ----------------- | ---------------- | -------------- |
| `ENTRY_POINT_V08` | All Users | |
| `accountId` | All Users | |
| `domainSeparator` | All Users | |
| `eip712Domain` | All Users | |
| `entryPoint` | All Users | |
1 change: 1 addition & 0 deletions packages/auth-server-api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"cors": "^2.8.5",
"dotenv": "^16.4.7",
"express": "^4.21.2",
"express-rate-limit": "^7.5.0",
"viem": "2.30.0",
"zksync-sso-4337": "workspace:*",
"zod": "^3.24.1"
Expand Down
8 changes: 5 additions & 3 deletions packages/auth-server-api/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import cors from "cors";
import express, { type NextFunction, type Request, type Response } from "express";

import { env } from "./config.js";
import { env, prividiumConfig } from "./config.js";
import { deployAccountHandler } from "./handlers/deploy-account.js";
import { prividiumAuthMiddleware } from "./middleware/prividium-auth.js";
import { deployLimiter } from "./middleware/rate-limit.js";

// Initialize Express app
const app = express();
Expand Down Expand Up @@ -33,8 +35,8 @@ app.get("/api/health", (_req: Request, res: Response) => {
res.json({ status: "ok", timestamp: new Date().toISOString() });
});

// Deploy account endpoint
app.post("/api/deploy-account", deployAccountHandler);
// Deploy account endpoint (rate limiting first, then auth, then handler)
app.post("/api/deploy-account", deployLimiter, prividiumAuthMiddleware(prividiumConfig), deployAccountHandler);

// Global error handler
// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand Down
69 changes: 66 additions & 3 deletions packages/auth-server-api/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,11 +34,20 @@ const envSchema = z.object({
CORS_ORIGINS: z.string().default("http://localhost:3002,http://localhost:3003,http://localhost:3004,http://localhost:3005,http://localhost:3000"),
DEPLOYER_PRIVATE_KEY: z.string().default("0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80"),
RPC_URL: z.string().default("http://127.0.0.1:8545"),
BUNDLER_URL: z.string().default("http://127.0.0.1:4337"),
FACTORY_ADDRESS: z.string().optional(),
EOA_VALIDATOR_ADDRESS: z.string().optional(),
WEBAUTHN_VALIDATOR_ADDRESS: z.string().optional(),
SESSION_VALIDATOR_ADDRESS: z.string().optional(),
// Prividium Mode Configuration
PRIVIDIUM_MODE: z.string().transform((v) => v === "true").default("false"),
PRIVIDIUM_PERMISSIONS_BASE_URL: z.string().optional(),
PRIVIDIUM_RPC_PROXY_BASE_URL: z.string().optional(),
PRIVIDIUM_ADMIN_PRIVATE_KEY: z.string().optional(),
PRIVIDIUM_TEMPLATE_KEY: z.string().optional(),
SSO_AUTH_SERVER_BASE_URL: z.string().optional(),
// Rate Limiting Configuration
RATE_LIMIT_DEPLOY_MAX: z.string().default("20"),
RATE_LIMIT_DEPLOY_WINDOW_MS: z.string().default("3600000"), // 1 hour
});

// Parse and validate environment variables
Expand All @@ -50,6 +59,21 @@ try {
process.exit(1);
}

// Validate Prividium configuration when enabled
if (env.PRIVIDIUM_MODE) {
const missingPrividiumVars: string[] = [];
if (!env.PRIVIDIUM_PERMISSIONS_BASE_URL) missingPrividiumVars.push("PRIVIDIUM_PERMISSIONS_BASE_URL");
if (!env.PRIVIDIUM_RPC_PROXY_BASE_URL) missingPrividiumVars.push("PRIVIDIUM_RPC_PROXY_BASE_URL");
if (!env.PRIVIDIUM_ADMIN_PRIVATE_KEY) missingPrividiumVars.push("PRIVIDIUM_ADMIN_PRIVATE_KEY");
if (!env.PRIVIDIUM_TEMPLATE_KEY) missingPrividiumVars.push("PRIVIDIUM_TEMPLATE_KEY");
if (!env.SSO_AUTH_SERVER_BASE_URL) missingPrividiumVars.push("SSO_AUTH_SERVER_BASE_URL");

if (missingPrividiumVars.length > 0) {
console.error("PRIVIDIUM_MODE is enabled but missing required configuration:", missingPrividiumVars.join(", "));
process.exit(1);
}
}

// Use env vars if provided, otherwise fall back to contracts.json
const FACTORY_ADDRESS = env.FACTORY_ADDRESS || contractsFromFile.factory;
const EOA_VALIDATOR_ADDRESS = env.EOA_VALIDATOR_ADDRESS || contractsFromFile.eoaValidator;
Expand Down Expand Up @@ -89,7 +113,21 @@ const zksyncOsTestnet = defineChain({
},
},
});
const SUPPORTED_CHAINS: Chain[] = [localhost, zksyncOsTestnet];
const zksyncOsLocal = defineChain({
id: 6565,
name: "ZKsyncOS Local",
nativeCurrency: {
name: "Ether",
symbol: "ETH",
decimals: 18,
},
rpcUrls: {
default: {
http: ["http://localhost:5050"],
},
},
});
const SUPPORTED_CHAINS: Chain[] = [localhost, zksyncOsTestnet, zksyncOsLocal];

function getChain(chainId: number): Chain {
const chain = SUPPORTED_CHAINS.find((c) => c.id === chainId);
Expand All @@ -99,4 +137,29 @@ function getChain(chainId: number): Chain {
return chain;
}

export { env, EOA_VALIDATOR_ADDRESS, FACTORY_ADDRESS, getChain, SESSION_VALIDATOR_ADDRESS, SUPPORTED_CHAINS, WEBAUTHN_VALIDATOR_ADDRESS };
// Prividium configuration object for services
export interface PrividiumConfig {
enabled: boolean;
permissionsApiUrl: string;
proxyUrl: string;
adminPrivateKey: string;
templateKey: string;
ssoAuthServerBaseUrl: string;
}

const prividiumConfig: PrividiumConfig = {
enabled: env.PRIVIDIUM_MODE,
permissionsApiUrl: env.PRIVIDIUM_PERMISSIONS_BASE_URL || "",
proxyUrl: env.PRIVIDIUM_RPC_PROXY_BASE_URL ? `${env.PRIVIDIUM_RPC_PROXY_BASE_URL}/rpc` : "",
adminPrivateKey: env.PRIVIDIUM_ADMIN_PRIVATE_KEY || "",
templateKey: env.PRIVIDIUM_TEMPLATE_KEY || "",
ssoAuthServerBaseUrl: env.SSO_AUTH_SERVER_BASE_URL || "",
};

// Rate limiting configuration
const rateLimitConfig = {
deployMax: parseInt(env.RATE_LIMIT_DEPLOY_MAX, 10),
deployWindowMs: parseInt(env.RATE_LIMIT_DEPLOY_WINDOW_MS, 10),
};

export { env, EOA_VALIDATOR_ADDRESS, FACTORY_ADDRESS, getChain, prividiumConfig, rateLimitConfig, SESSION_VALIDATOR_ADDRESS, SUPPORTED_CHAINS, WEBAUTHN_VALIDATOR_ADDRESS };
Loading
Loading