Skip to content

Commit 502c99f

Browse files
committed
Merge branch 'main' of github.com:efdevcon/monorepo
2 parents 61e5e2c + 1dd805a commit 502c99f

11 files changed

Lines changed: 2641 additions & 1343 deletions

File tree

devconnect-app/EIP7702_SETUP.md

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
# EIP-7702 with Para + Alchemy Setup
2+
3+
Gasless USDC transactions for Para wallets using EIP-7702 temporary account upgrades and Alchemy Account Kit.
4+
5+
## Overview
6+
7+
- **What**: EOA wallets (Para) get temporary smart account functionality for gas sponsorship
8+
- **How**: EIP-7702 authorization + Alchemy Gas Manager
9+
- **Benefit**: Zero gas fees for USDC transfers on Base
10+
11+
## Architecture
12+
13+
```
14+
Para Wallet (EOA)
15+
16+
Custom Signature Utilities (para-signature-utils.ts)
17+
18+
EIP-7702 Authorization Signing
19+
20+
Alchemy Modular Account V2 (mode: "7702")
21+
22+
Alchemy Gas Manager (sponsored transaction)
23+
24+
Base Network (confirmed transaction)
25+
```
26+
27+
## Key Files
28+
29+
### 1. Signature Utilities
30+
**`src/lib/para-signature-utils.ts`**
31+
- Custom signing methods that bypass Ethereum Signed Message prefix
32+
- Uses viem's `hashAuthorization`, `hashMessage`, `hashTypedData`
33+
- Properly formats v-values (0/1 for EIP-7702, 27/28 for standard)
34+
35+
### 2. Configuration
36+
**`src/config/eip7702.ts`**
37+
```typescript
38+
export const EIP7702_CONFIG = {
39+
ENABLED: process.env.NEXT_PUBLIC_ENABLE_EIP7702 === 'true',
40+
ALCHEMY_RPC_URL: process.env.NEXT_PUBLIC_ALCHEMY_RPC_URL,
41+
ALCHEMY_GAS_POLICY_ID: process.env.NEXT_PUBLIC_ALCHEMY_GAS_POLICY_ID,
42+
USDC_CONTRACT: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913',
43+
USDC_DECIMALS: 6,
44+
CHAIN_ID: 8453, // Base
45+
};
46+
```
47+
48+
### 3. Transaction Hook
49+
**`src/hooks/useParaEIP7702Transaction.ts`**
50+
- Creates extended viem account with custom signing methods
51+
- Overrides: `signAuthorization`, `signMessage`, `signTypedData`
52+
- Uses Alchemy's `createModularAccountV2Client` with `mode: "7702"`
53+
54+
### 4. Router
55+
**`src/hooks/useTransactionRouter.ts`**
56+
- Switches between legacy (backend relayer) and EIP-7702 (Alchemy) systems
57+
- Based on `NEXT_PUBLIC_ENABLE_EIP7702` feature flag
58+
59+
## Environment Variables
60+
61+
```bash
62+
# Enable EIP-7702
63+
NEXT_PUBLIC_ENABLE_EIP7702=true
64+
65+
# Alchemy Configuration
66+
NEXT_PUBLIC_ALCHEMY_RPC_URL=https://base-mainnet.g.alchemy.com/v2/YOUR_API_KEY
67+
NEXT_PUBLIC_ALCHEMY_GAS_POLICY_ID=your-gas-policy-id
68+
```
69+
70+
## Alchemy Setup
71+
72+
1. **Create Account**: https://dashboard.alchemy.com
73+
2. **Create App**: Base Mainnet
74+
3. **Configure Gas Manager**:
75+
- Go to Gas Manager
76+
- Create Policy
77+
- Set spending limits
78+
- Configure allowlist (optional)
79+
4. **Copy Credentials**:
80+
- RPC URL from app dashboard
81+
- Policy ID from Gas Manager
82+
83+
## How It Works
84+
85+
### Legacy System (Before)
86+
```typescript
87+
User signs EIP-712Backend relayerPays gasUSDC transfer
88+
```
89+
90+
### EIP-7702 System (Now)
91+
```typescript
92+
User signs EIP-7702 authTemporary account upgrade
93+
Alchemy sponsors gasUSDC transferAccount reverts to EOA
94+
```
95+
96+
## Technical Details
97+
98+
### Why Custom Signature Utilities?
99+
100+
Para's standard signing methods add Ethereum Signed Message prefix:
101+
```typescript
102+
keccak256("\x19Ethereum Signed Message:\n32" + message)
103+
```
104+
105+
EIP-7702 requires raw signatures:
106+
```typescript
107+
keccak256(message) // No prefix!
108+
```
109+
110+
Our custom utilities:
111+
1. Hash the data with viem's proper hash functions
112+
2. Sign the hash directly with Para's `signMessage`
113+
3. Adjust v-values correctly for each context
114+
115+
### Signature v-value Handling
116+
117+
- **Standard Ethereum**: v = 27 or 28
118+
- **EIP-7702**: yParity = 0 or 1
119+
120+
Our utilities automatically convert based on context.
121+
122+
## Testing
123+
124+
1. Set environment variables
125+
2. Enable feature flag: `NEXT_PUBLIC_ENABLE_EIP7702=true`
126+
3. Trigger USDC payment with Para wallet
127+
4. Check console logs for EIP-7702 flow
128+
5. Verify gas sponsorship in Alchemy dashboard
129+
130+
## Fallback Behavior
131+
132+
If EIP-7702 is disabled or misconfigured, automatically falls back to legacy backend relayer system.
133+
134+
## Dependencies
135+
136+
```json
137+
{
138+
"@account-kit/smart-contracts": "^4.70.0",
139+
"@account-kit/infra": "^4.70.0",
140+
"@aa-sdk/core": "^4.70.0",
141+
"@getpara/react-sdk": "^2.0.0-alpha.63"
142+
}
143+
```
144+
145+
## Console Logs (Success)
146+
147+
```
148+
🔄 [EIP-7702] Starting EIP-7702 transaction with Alchemy Account Kit
149+
🔄 [EIP-7702] Signing EIP-7702 authorization with Para custom utilities...
150+
✅ [EIP-7702] Authorization signed successfully!
151+
🔄 [EIP-7702] Signing message with Para custom utilities...
152+
✅ [EIP-7702] Message signed successfully
153+
✅ [EIP-7702] UserOperation submitted
154+
✅ [EIP-7702] Transaction confirmed
155+
```
156+
157+
## Troubleshooting
158+
159+
### "User operation cost exceeds specified spend limit"
160+
**Solution**: Increase spending limit in Alchemy Gas Manager policy
161+
162+
### "Invalid account signature"
163+
**Solution**: Verify all signing methods are using custom utilities
164+
165+
### "Invalid 7702 Auth signature"
166+
**Solution**: Check RLP encoding and v-value formatting
167+
168+
## References
169+
170+
- [EIP-7702 Specification](https://eips.ethereum.org/EIPS/eip-7702)
171+
- [Alchemy Account Kit](https://accountkit.alchemy.com/)
172+
- [Para EIP-7702 Guide](https://docs.para.gg/v2/react/guides/account-abstraction/eip7702-alchemy)
173+

devconnect-app/package.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414
"q": "npx tsx scripts/fetch-quests.ts"
1515
},
1616
"dependencies": {
17+
"@aa-sdk/core": "^4.70.0",
18+
"@account-kit/infra": "^4.70.0",
19+
"@account-kit/smart-contracts": "^4.70.0",
1720
"@base-org/account": "^2.2.0",
1821
"@coinbase/cdp-sdk": "^1.0.0",
1922
"@cosmjs/cosmwasm-stargate": "^0.34.0",
@@ -25,7 +28,9 @@
2528
"@farcaster/miniapp-sdk": "^0.1.8",
2629
"@farcaster/miniapp-wagmi-connector": "^1.0.0",
2730
"@getpara/graz": "2.0.0-alpha.19",
31+
"@getpara/react-common": "2.0.0-alpha.63",
2832
"@getpara/react-sdk": "2.0.0-alpha.63",
33+
"@getpara/viem-v2-integration": "2.0.0-alpha.63",
2934
"@getpara/wagmi-v2-integration": "2.0.0-alpha.63",
3035
"@leapwallet/cosmos-social-login-capsule-provider": "^0.0.44",
3136
"@netlify/plugin-nextjs": "^5.13.5",
@@ -62,6 +67,7 @@
6267
"next": "16.0.0-beta.0",
6368
"next-themes": "^0.4.6",
6469
"panzoom": "^9.4.3",
70+
"permissionless": "^0.2.57",
6571
"pino-pretty": "^13.1.1",
6672
"qrcode": "^1.5.4",
6773
"qrcode.react": "^4.2.0",
@@ -74,7 +80,7 @@
7480
"starknet": "^7.6.4",
7581
"tailwind-merge": "^3.3.1",
7682
"usehooks-ts": "^3.1.1",
77-
"viem": "^2.37.11",
83+
"viem": "^2.38.2",
7884
"wagmi": "^2.17.5",
7985
"zustand": "^5.0.7"
8086
},

devconnect-app/src/app/api/auth/tickets/pretix.ts

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,14 @@
11
import stores from './pretix-stores-list';
22

3+
interface PretixItem {
4+
id: number;
5+
name: string | { en: string;[key: string]: string };
6+
description?: string | { en: string;[key: string]: string };
7+
category?: string;
8+
active?: boolean;
9+
[key: string]: any;
10+
}
11+
312
export async function getPaidTicketsByEmail(
413
email: string,
514
storeID = 'devconnect'
@@ -30,7 +39,7 @@ export async function getPaidTicketsByEmail(
3039
}
3140

3241
const itemsData = await itemsResponse.json();
33-
const itemsMap = new Map(
42+
const itemsMap = new Map<number, PretixItem>(
3443
itemsData.results.map((item: any) => [item.id, item])
3544
);
3645

@@ -72,23 +81,26 @@ export async function getPaidTicketsByEmail(
7281
const addons = order.positions
7382
.filter((p: any) => p.addon_to === position.id)
7483
.map((addon: any) => {
75-
const itemDetails = itemsMap.get(addon.item) as any;
84+
const itemDetails = itemsMap.get(addon.item);
85+
const name = itemDetails?.name;
86+
const description = itemDetails?.description;
7687
return {
7788
id: addon.item,
7889
secret: addon.secret,
7990
itemName:
80-
itemDetails?.name?.en ||
81-
itemDetails?.name ||
82-
`Item ${addon.item}`,
91+
typeof name === 'object' ? name.en : name || `Item ${addon.item}`,
8392
description:
84-
itemDetails?.description?.en || itemDetails?.description,
93+
typeof description === 'object' ? description.en : description,
8594
price: addon.price,
8695
attendeeName: addon.attendee_name,
8796
category: itemDetails?.category,
8897
active: itemDetails?.active,
8998
};
9099
});
91100

101+
const mainName = mainItemDetails?.name;
102+
const mainDescription = mainItemDetails?.description;
103+
92104
return {
93105
secret: position.secret,
94106
attendeeName: position.attendee_name,
@@ -97,12 +109,9 @@ export async function getPaidTicketsByEmail(
97109
// Use item details from the items endpoint
98110
itemId: position.item,
99111
itemName:
100-
mainItemDetails?.name?.en ||
101-
mainItemDetails?.name ||
102-
position.item_name ||
103-
'Ticket',
112+
typeof mainName === 'object' ? mainName.en : mainName || position.item_name || 'Ticket',
104113
itemDescription:
105-
mainItemDetails?.description?.en || mainItemDetails?.description,
114+
typeof mainDescription === 'object' ? mainDescription.en : mainDescription,
106115
addons: addons,
107116
};
108117
}),

devconnect-app/src/components/PaymentModal.tsx

Lines changed: 50 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import { toast } from 'sonner';
88
import { base } from '@base-org/account';
99
import { useWalletManager } from '@/hooks/useWalletManager';
1010
import { useTransaction } from '@/hooks/useTransaction';
11+
import { isEIP7702Available } from '@/config/eip7702';
1112
import TokenSelector from '@/components/payment/TokenSelector';
1213
import NetworkSelector from '@/components/payment/NetworkSelector';
1314
import StatusStep from '@/components/payment/StatusStep';
@@ -122,6 +123,9 @@ export default function PaymentModal({
122123
const [isAddingTransaction, setIsAddingTransaction] = useState(false);
123124
const [isInitialLoad, setIsInitialLoad] = useState(true);
124125

126+
// Check if EIP-7702 is available
127+
const isUsingEIP7702 = isPara && isEIP7702Available();
128+
125129
// PaymentForm state
126130
const [recipient, setRecipient] = useState('');
127131
const [amount, setAmount] = useState('0.01');
@@ -1257,6 +1261,24 @@ export default function PaymentModal({
12571261
Simulation Mode
12581262
</div>
12591263
)}
1264+
{isPara && isUsingEIP7702 && !isSystemSimulationMode && (
1265+
<div className="inline-flex items-center gap-1 bg-green-100 text-green-800 px-2 py-1 rounded-full text-xs font-medium">
1266+
<svg
1267+
className="h-3 w-3"
1268+
fill="none"
1269+
stroke="currentColor"
1270+
viewBox="0 0 24 24"
1271+
>
1272+
<path
1273+
strokeLinecap="round"
1274+
strokeLinejoin="round"
1275+
strokeWidth={2}
1276+
d="M13 10V3L4 14h7v7l9-11h-7z"
1277+
/>
1278+
</svg>
1279+
EIP-7702
1280+
</div>
1281+
)}
12601282
</div>
12611283

12621284
<button
@@ -1455,12 +1477,34 @@ export default function PaymentModal({
14551477
</div>
14561478
</div>
14571479
{isPara && (
1458-
<p className="text-[#ededf0] text-xs text-center">
1459-
<span className="font-bold">Para: </span>
1460-
<span className="font-normal">
1461-
This transaction is gas-free
1462-
</span>
1463-
</p>
1480+
<div className="space-y-1">
1481+
<p className="text-[#ededf0] text-xs text-center">
1482+
<span className="font-bold">Para: </span>
1483+
<span className="font-normal">
1484+
This transaction is gas-free
1485+
</span>
1486+
</p>
1487+
{isUsingEIP7702 && (
1488+
<p className="text-[#f6b613] text-xs text-center flex items-center justify-center gap-1">
1489+
<svg
1490+
className="h-3 w-3"
1491+
fill="none"
1492+
stroke="currentColor"
1493+
viewBox="0 0 24 24"
1494+
>
1495+
<path
1496+
strokeLinecap="round"
1497+
strokeLinejoin="round"
1498+
strokeWidth={2}
1499+
d="M13 10V3L4 14h7v7l9-11h-7z"
1500+
/>
1501+
</svg>
1502+
<span className="font-semibold">
1503+
EIP-7702 Enabled
1504+
</span>
1505+
</p>
1506+
)}
1507+
</div>
14641508
)}
14651509
</div>
14661510
{/* <button className="text-[#1b6fae] text-sm font-medium">

0 commit comments

Comments
 (0)