Skip to content

Commit ee88008

Browse files
authored
Update AA demo app for V1 contracts and access control changes (#3632)
1 parent 2e7b73b commit ee88008

File tree

14 files changed

+4761
-90
lines changed

14 files changed

+4761
-90
lines changed
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
# ABI Synchronization Documentation
2+
3+
## Overview
4+
5+
This document explains the automated ABI synchronization system that keeps the demo app in sync with the smart contracts, even when contract names change (e.g., V1 naming).
6+
7+
## Automated Workflow
8+
9+
### 1. During Deployment (`deploy-local.sh`)
10+
- Deploys V1 contracts: `EntryPointV1`, `OmniAccountFactoryV1`, etc.
11+
- Saves deployment artifacts to `deployments/local/local.json` with:
12+
- Contract addresses
13+
- Full ABIs
14+
- Metadata (for tokens)
15+
- Automatically runs `sync-abis-from-deployment.sh` if available
16+
17+
### 2. ABI Synchronization (`sync-abis-from-deployment.sh`)
18+
- Reads deployment artifacts from `deployments/local/local.json`
19+
- Maps V1 contract names to demo app expected names:
20+
- `EntryPointV1``EntryPoint.json`
21+
- `OmniAccountFactoryV1``OmniAccountFactory.json`
22+
- Extracts `OmniAccountV1` ABI from compiled artifacts
23+
- Saves all ABIs to `aa-demo-app/src/contracts/abis/`
24+
25+
### 3. Address Update (`update-demo-addresses.sh`)
26+
- Primary source: deployment artifacts (`deployments/local/local.json`)
27+
- Fallback: broadcast files
28+
- Automatically runs ABI sync after updating addresses
29+
- Updates `.env.local` with contract addresses
30+
31+
## Manual Usage
32+
33+
### Sync ABIs Only
34+
```bash
35+
./sync-abis-from-deployment.sh
36+
```
37+
38+
### Update Addresses and ABIs
39+
```bash
40+
./update-demo-addresses.sh
41+
```
42+
43+
### For Different Environments
44+
```bash
45+
DEPLOYMENT_ENV=staging ./sync-abis-from-deployment.sh
46+
DEPLOYMENT_ENV=staging ./update-demo-addresses.sh
47+
```
48+
49+
## Benefits
50+
51+
1. **Single Source of Truth**: Deployment artifacts contain everything
52+
2. **Automatic V1 Mapping**: No need to update demo app for V1 naming
53+
3. **Version Agnostic**: Works with any contract version naming
54+
4. **Environment Support**: Easy switching between local/staging/production
55+
5. **No Manual Compilation**: Reuses existing artifacts
56+
57+
## Troubleshooting
58+
59+
### Missing OmniAccount ABI
60+
The script will automatically run `forge build` if needed to generate the OmniAccountV1 artifact.
61+
62+
### Multiple Test Tokens
63+
The script handles multiple TestToken instances by checking metadata for USDC/USDT symbols.
64+
65+
### Custom Networks
66+
Set `DEPLOYMENT_ENV` to use different deployment files:
67+
```bash
68+
DEPLOYMENT_ENV=arbitrum-sepolia ./sync-abis-from-deployment.sh
69+
```

tee-worker/omni-executor/aa-contracts/aa-demo-app/README.md

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -284,21 +284,28 @@ aa-demo-app/
284284
│ ├── app/ # Next.js app router pages
285285
│ ├── components/ # React components
286286
│ │ ├── AccountsDashboard.tsx # Displays wallet and OmniAccount balances
287-
│ │ ├── AuthorizedSigners.tsx # Manage authorized signers
288-
│ │ ├── AuthorizeTEEWorker.tsx # TEE worker authorization flow
287+
│ │ ├── AuthorizedSigners.tsx # Manage authorized signers (direct calls, no execute wrapper)
288+
│ │ ├── AuthorizeTEEWorker.tsx # TEE worker authorization flow (uses Owner signer type)
289289
│ │ ├── FundingGuide.tsx # ETH funding guide
290290
│ │ ├── TEETokenTransfer.tsx # Token transfer through TEE worker
291291
│ │ ├── CreateOmniAccount.tsx # Smart account creation flow with paymaster option
292292
│ │ └── WalletConnect.tsx # Wallet connection component
293-
│ ├── contracts/ # Contract ABIs
294-
│ │ ├── ...existing ABIs
293+
│ ├── contracts/ # Contract ABIs (auto-synced from V1 contracts)
294+
│ │ ├── EntryPoint.json # Synced from EntryPointV1
295+
│ │ ├── OmniAccount.json # Synced from OmniAccountV1
296+
│ │ ├── OmniAccountFactory.json # Synced from OmniAccountFactoryV1
295297
│ │ └── SimplePaymaster.json # Paymaster contract ABI
296298
│ └── lib/ # Utilities and configuration
297299
│ ├── aa-utils.ts # AA utilities including UserOp construction
298300
│ ├── constants.ts # Contract addresses and token configs
299301
│ ├── tee-worker-client.ts # TEE Worker RPC client with submitUserOpTest
300302
│ └── wagmi.ts # Web3 configuration
301303
└── public/ # Static assets
304+
305+
Parent directory scripts:
306+
├── sync-abis-from-deployment.sh # Syncs V1 contract ABIs to demo app
307+
├── update-demo-addresses.sh # Updates addresses and runs ABI sync
308+
└── deploy-local.sh # Deploys contracts and auto-syncs ABIs
302309
```
303310

304311
## Troubleshooting
@@ -336,6 +343,12 @@ You might see errors like `execution reverted` for `symbol()` or `decimals()` ca
336343
- **Transaction fails with paymaster**: Ensure the paymaster is properly configured
337344
- **DemoPaymaster vs SimplePaymaster**: DemoPaymaster accepts all operations (testing only), SimplePaymaster requires authorized bundlers
338345

346+
### Signer Management Issues
347+
- **"Transaction reverted" when adding signers**: Ensure you're connected with the account owner (not a root signer)
348+
- **"Only owner" errors**: The connected wallet must be the original account creator
349+
- **Authorization failures**: Check that the UserOperation is signed with `UserOpSigner.Owner` type for restricted functions
350+
- **TEE Worker not added**: Verify the transaction succeeded and check the signer list
351+
339352
## Environment Variables
340353

341354
The app uses these environment variables:
@@ -411,6 +424,23 @@ export const PAYMASTER_CONFIG = {
411424

412425
## Technical Details
413426

427+
### Contract Versions and ABI Management
428+
429+
The demo app works with V1 contracts (`OmniAccountV1`, `OmniAccountFactoryV1`, `EntryPointV1`) while maintaining backward-compatible naming:
430+
431+
- **Automatic ABI Synchronization**: The `sync-abis-from-deployment.sh` script automatically maps V1 contract ABIs to expected names
432+
- **Deployment Integration**: Running `./deploy-local.sh` automatically syncs ABIs after deployment
433+
- **Version Support**: The contracts include a `version()` function returning "1.0.0"
434+
435+
### Access Control and Signer Management
436+
437+
Recent updates to the smart contracts have enhanced access control:
438+
439+
- **Direct EntryPoint Calls**: The `onlyOwner` modifier now allows the EntryPoint to directly call restricted functions
440+
- **No Execute Wrapper Needed**: Functions like `addRootSigner` and `removeRootSigner` are called directly in UserOperations
441+
- **Signer Type Requirements**: Only `UserOpSigner.Owner` can call restricted functions (not `RootKey` or `SessionKey`)
442+
- **Signer Hierarchy**: For non-EVM owners, passkey signers have priority over root signers (when passkeys are present)
443+
414444
### Paymaster Integration
415445

416446
The app integrates paymaster functionality for gas sponsorship:
@@ -419,12 +449,13 @@ The app integrates paymaster functionality for gas sponsorship:
419449
- **Balance Checking**: Verifies paymaster has sufficient deposit at EntryPoint
420450
- **Dynamic Toggle**: Users can enable/disable paymaster per transaction
421451

422-
### New Utility Functions
452+
### Key Utility Functions
423453

424454
- `buildTokenTransferUserOp()`: Creates UserOperation for ERC20 token transfers
425455
- `buildERC20TransferCallData()`: Encodes ERC20 transfer function call
426456
- `toSerializablePackedUserOperation()`: Converts PackedUserOperation to serializable format
427457
- `submitUserOpTest()`: Submits UserOperations through TEE worker RPC
458+
- `signUserOperation()`: Signs UserOperations with proper signer type validation
428459

429460
### RPC Method Updates
430461

tee-worker/omni-executor/aa-contracts/aa-demo-app/src/components/AuthorizeTEEWorker.tsx

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -92,32 +92,13 @@ export function AuthorizeTEEWorker({
9292
// Step 2: Add the TEE worker as an authorized signer
9393
setIsAddingSigner(true);
9494

95-
// First encode the addRootSigner call
96-
const addSignerData = encodeFunctionData({
95+
// Directly encode the addRootSigner call (no execute wrapper needed)
96+
const callData = encodeFunctionData({
9797
abi: CONTRACTS.OmniAccountImplementation.abi,
9898
functionName: "addRootSigner",
9999
args: [teeWorkerAddress as `0x${string}`],
100100
});
101101

102-
// Then wrap it in an execute call (the account calls itself)
103-
const callData = encodeFunctionData({
104-
abi: [
105-
{
106-
name: "execute",
107-
type: "function",
108-
inputs: [
109-
{ name: "target", type: "address" },
110-
{ name: "value", type: "uint256" },
111-
{ name: "data", type: "bytes" },
112-
],
113-
outputs: [],
114-
stateMutability: "nonpayable",
115-
},
116-
],
117-
functionName: "execute",
118-
args: [omniAccountAddress as `0x${string}`, BigInt(0), addSignerData],
119-
});
120-
121102
// Get current nonce for the account
122103
const nonce = (await publicClient.readContract({
123104
address: CONTRACTS.EntryPoint.address,
@@ -145,14 +126,14 @@ export function AuthorizeTEEWorker({
145126
: undefined,
146127
});
147128

148-
// Sign UserOperation with RootKey signer type
129+
// Sign UserOperation with Owner signer type (required for restricted functions)
149130
const signature = await signUserOperation(
150131
walletClient,
151132
evmAddress,
152133
userOp as UserOperation,
153134
CONTRACTS.EntryPoint.address,
154135
BigInt(await publicClient.getChainId()),
155-
UserOpSigner.RootKey,
136+
UserOpSigner.Owner,
156137
);
157138

158139
userOp.signature = signature;

tee-worker/omni-executor/aa-contracts/aa-demo-app/src/components/AuthorizedSigners.tsx

Lines changed: 9 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -101,36 +101,14 @@ export function AuthorizedSigners({
101101

102102
setIsAddingSigner(true);
103103
try {
104-
// IMPORTANT: We need to wrap the addRootSigner call in an execute call
105-
// This is because the EntryPoint calls the account, and the account needs
106-
// to call itself to satisfy the onlyOwner modifier (msg.sender == address(this))
107-
108-
// First encode the addRootSigner call
109-
const addSignerData = encodeFunctionData({
104+
// Directly encode the addRootSigner call
105+
// The EntryPoint can call restricted functions on behalf of the owner
106+
const callData = encodeFunctionData({
110107
abi: CONTRACTS.OmniAccountImplementation.abi,
111108
functionName: "addRootSigner",
112109
args: [newSignerAddress as `0x${string}`],
113110
});
114111

115-
// Then wrap it in an execute call (the account calls itself)
116-
const callData = encodeFunctionData({
117-
abi: [
118-
{
119-
name: "execute",
120-
type: "function",
121-
inputs: [
122-
{ name: "target", type: "address" },
123-
{ name: "value", type: "uint256" },
124-
{ name: "data", type: "bytes" },
125-
],
126-
outputs: [],
127-
stateMutability: "nonpayable",
128-
},
129-
],
130-
functionName: "execute",
131-
args: [omniAccountAddress as `0x${string}`, BigInt(0), addSignerData],
132-
});
133-
134112
// Get current nonce for the account
135113
const nonce = (await publicClient.readContract({
136114
address: CONTRACTS.EntryPoint.address,
@@ -158,14 +136,14 @@ export function AuthorizedSigners({
158136
: undefined,
159137
});
160138

161-
// Sign UserOperation with RootKey signer type
139+
// Sign UserOperation with Owner signer type (required for restricted functions)
162140
const signature = await signUserOperation(
163141
walletClient,
164142
evmAddress,
165143
userOp as UserOperation,
166144
CONTRACTS.EntryPoint.address,
167145
BigInt(await publicClient.getChainId()),
168-
UserOpSigner.RootKey,
146+
UserOpSigner.Owner,
169147
);
170148

171149
userOp.signature = signature;
@@ -237,36 +215,13 @@ export function AuthorizedSigners({
237215
return;
238216

239217
try {
240-
// First encode the removeRootSigner call
241-
const removeSignerData = encodeFunctionData({
218+
// Directly encode the removeRootSigner call
219+
const callData = encodeFunctionData({
242220
abi: CONTRACTS.OmniAccountImplementation.abi,
243221
functionName: "removeRootSigner",
244222
args: [signerToRemove as `0x${string}`],
245223
});
246224

247-
// Then wrap it in an execute call (the account calls itself)
248-
const callData = encodeFunctionData({
249-
abi: [
250-
{
251-
name: "execute",
252-
type: "function",
253-
inputs: [
254-
{ name: "target", type: "address" },
255-
{ name: "value", type: "uint256" },
256-
{ name: "data", type: "bytes" },
257-
],
258-
outputs: [],
259-
stateMutability: "nonpayable",
260-
},
261-
],
262-
functionName: "execute",
263-
args: [
264-
omniAccountAddress as `0x${string}`,
265-
BigInt(0),
266-
removeSignerData,
267-
],
268-
});
269-
270225
// Get current nonce for the account
271226
const nonce = (await publicClient.readContract({
272227
address: CONTRACTS.EntryPoint.address,
@@ -294,14 +249,14 @@ export function AuthorizedSigners({
294249
: undefined,
295250
});
296251

297-
// Sign UserOperation with RootKey signer type
252+
// Sign UserOperation with Owner signer type (required for restricted functions)
298253
const signature = await signUserOperation(
299254
walletClient,
300255
evmAddress,
301256
userOp as UserOperation,
302257
CONTRACTS.EntryPoint.address,
303258
BigInt(await publicClient.getChainId()),
304-
UserOpSigner.RootKey,
259+
UserOpSigner.Owner,
305260
);
306261

307262
userOp.signature = signature;

tee-worker/omni-executor/aa-contracts/aa-demo-app/src/contracts/abis/EntryPoint.json

Lines changed: 1068 additions & 1 deletion
Large diffs are not rendered by default.

tee-worker/omni-executor/aa-contracts/aa-demo-app/src/contracts/abis/IEntryPoint.json

Lines changed: 1068 additions & 1 deletion
Large diffs are not rendered by default.

tee-worker/omni-executor/aa-contracts/aa-demo-app/src/contracts/abis/OmniAccount.json

Lines changed: 866 additions & 1 deletion
Large diffs are not rendered by default.

tee-worker/omni-executor/aa-contracts/aa-demo-app/src/contracts/abis/OmniAccountFactory.json

Lines changed: 122 additions & 1 deletion
Large diffs are not rendered by default.

tee-worker/omni-executor/aa-contracts/aa-demo-app/src/contracts/abis/SimplePaymaster.json

Lines changed: 468 additions & 1 deletion
Large diffs are not rendered by default.

0 commit comments

Comments
 (0)