Skip to content

Commit e311042

Browse files
committed
feat: add Dynamic support to verbs
1 parent 4930704 commit e311042

22 files changed

+686
-406
lines changed

packages/demo/backend/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
},
3838
"dependencies": {
3939
"@clerk/backend": "^2.12.0",
40+
"@dynamic-labs-wallet/node": "^0.0.158",
41+
"@dynamic-labs-wallet/node-evm": "^0.0.158",
4042
"@eth-optimism/utils-app": "^0.0.6",
4143
"@eth-optimism/verbs-sdk": "workspace:*",
4244
"@eth-optimism/viem": "^0.4.13",

packages/demo/backend/src/config/env.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,4 +59,6 @@ export const env = cleanEnv(process.env, {
5959
BASE_SEPOLIA_BUNDER_URL: str({ devDefault: 'dummy' }),
6060
UNICHAIN_BUNDLER_URL: str({ devDefault: 'dummy' }),
6161
UNICHAIN_BUNDLER_SPONSORSHIP_POLICY: str({ devDefault: 'dummy' }),
62+
DYNAMIC_AUTH_TOKEN: str({ devDefault: 'dummy' }),
63+
DYNAMIC_ENVIRONMENT_ID: str({ devDefault: 'dummy' }),
6264
})

packages/demo/backend/src/config/verbs.ts

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,20 @@
1+
import { DynamicEvmWalletClient } from '@dynamic-labs-wallet/node-evm'
12
import { Verbs, type VerbsConfig } from '@eth-optimism/verbs-sdk'
23
import { PrivyClient } from '@privy-io/server-auth'
34
import { baseSepolia, unichain } from 'viem/chains'
45

56
import { env } from './env.js'
67

7-
let verbsInstance: Verbs<'privy'>
8+
let verbsInstance: Verbs<'dynamic'>
89

9-
export function createVerbsConfig(): VerbsConfig<'privy'> {
10+
export function createVerbsConfig(): VerbsConfig<'dynamic'> {
1011
return {
1112
wallet: {
1213
hostedWalletConfig: {
1314
provider: {
14-
type: 'privy',
15+
type: 'dynamic',
1516
config: {
16-
privyClient: new PrivyClient(
17-
env.PRIVY_APP_ID,
18-
env.PRIVY_APP_SECRET,
19-
),
17+
dynamicClient: getDynamicClient(),
2018
},
2119
},
2220
},
@@ -55,7 +53,7 @@ export function createVerbsConfig(): VerbsConfig<'privy'> {
5553
}
5654
}
5755

58-
export function initializeVerbs(config?: VerbsConfig<'privy'>): void {
56+
export function initializeVerbs(config?: VerbsConfig<'dynamic'>): void {
5957
const verbsConfig = config || createVerbsConfig()
6058
verbsInstance = new Verbs(verbsConfig)
6159
}
@@ -70,3 +68,10 @@ export function getVerbs() {
7068
export function getPrivyClient() {
7169
return new PrivyClient(env.PRIVY_APP_ID, env.PRIVY_APP_SECRET)
7270
}
71+
72+
export function getDynamicClient() {
73+
return new DynamicEvmWalletClient({
74+
authToken: env.DYNAMIC_AUTH_TOKEN,
75+
environmentId: env.DYNAMIC_ENVIRONMENT_ID,
76+
})
77+
}

packages/demo/backend/src/controllers/lend.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@ import { serializeBigInt } from '../utils/serializers.js'
99

1010
const DepositRequestSchema = z.object({
1111
body: z.object({
12-
walletId: z.string().min(1, 'walletId is required'),
12+
walletAddress: z
13+
.string()
14+
.regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid wallet address format')
15+
.trim(),
1316
amount: z.number().positive('amount must be positive'),
1417
tokenAddress: z
1518
.string()
@@ -31,7 +34,10 @@ const VaultBalanceParamsSchema = z.object({
3134
vaultAddress: z
3235
.string()
3336
.regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid vault address format'),
34-
walletId: z.string().min(1, 'walletId is required'),
37+
walletAddress: z
38+
.string()
39+
.regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid wallet address format')
40+
.trim(),
3541
}),
3642
})
3743

@@ -91,11 +97,11 @@ export class LendController {
9197
if (!validation.success) return validation.response
9298

9399
const {
94-
params: { vaultAddress, walletId },
100+
params: { vaultAddress, walletAddress },
95101
} = validation.data
96102
const balance = await lendService.getVaultBalance(
97103
vaultAddress as Address,
98-
walletId,
104+
walletAddress as Address,
99105
)
100106
const formattedBalance =
101107
await lendService.formatVaultBalanceResponse(balance)
@@ -120,16 +126,16 @@ export class LendController {
120126
if (!validation.success) return validation.response
121127

122128
const {
123-
body: { walletId, amount, tokenAddress, chainId },
129+
body: { walletAddress, amount, tokenAddress, chainId },
124130
} = validation.data
125131
const lendTransaction = await lendService.deposit(
126-
walletId,
132+
walletAddress as Address,
127133
amount,
128134
tokenAddress as Address,
129135
chainId as SupportedChainId,
130136
)
131137
const result = await lendService.executeLendTransaction(
132-
walletId,
138+
walletAddress as Address,
133139
lendTransaction,
134140
chainId as SupportedChainId,
135141
)

packages/demo/backend/src/controllers/wallet.ts

Lines changed: 32 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { Context } from 'hono'
22
import type { Address } from 'viem'
3+
import { getAddress } from 'viem'
34
import { z } from 'zod'
45

56
import type {
@@ -18,15 +19,30 @@ const UserIdParamSchema = z.object({
1819
}),
1920
})
2021

22+
const WalletAddressParamSchema = z.object({
23+
params: z.object({
24+
walletAddress: z
25+
.string()
26+
.regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid wallet address format')
27+
.trim(),
28+
}),
29+
})
30+
2131
const FundWalletRequestSchema = z.object({
2232
params: z.object({
23-
userId: z.string().min(1, 'User ID is required').trim(),
33+
walletAddress: z
34+
.string()
35+
.regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid wallet address format')
36+
.trim(),
2437
}),
2538
})
2639

2740
const SendTokensRequestSchema = z.object({
2841
body: z.object({
29-
walletId: z.string().min(1, 'walletId is required'),
42+
walletAddress: z
43+
.string()
44+
.regex(/^0x[a-fA-F0-9]{40}$/, 'Invalid wallet address format')
45+
.trim(),
3046
amount: z.number().positive('amount must be positive'),
3147
recipientAddress: z
3248
.string()
@@ -56,11 +72,11 @@ export class WalletController {
5672
const {
5773
params: { userId },
5874
} = validation.data
59-
const { privyAddress, smartWalletAddress } =
75+
const { signerAddress, smartWalletAddress } =
6076
await walletService.createWallet()
6177

6278
return c.json({
63-
privyAddress,
79+
signerAddress,
6480
smartWalletAddress,
6581
userId,
6682
} satisfies CreateWalletResponse)
@@ -81,27 +97,27 @@ export class WalletController {
8197
*/
8298
async getWallet(c: Context) {
8399
try {
84-
const validation = await validateRequest(c, UserIdParamSchema)
100+
const validation = await validateRequest(c, WalletAddressParamSchema)
85101
if (!validation.success) return validation.response
86102

87103
const {
88-
params: { userId },
104+
params: { walletAddress },
89105
} = validation.data
90-
const wallet = await walletService.getWallet(userId)
106+
const wallet = await walletService.getWallet(getAddress(walletAddress))
91107

92108
if (!wallet) {
93109
return c.json(
94110
{
95111
error: 'Wallet not found',
96-
message: `No wallet found for user ${userId}`,
112+
message: `No wallet found for user ${walletAddress}`,
97113
},
98114
404,
99115
)
100116
}
101117

102118
return c.json({
103119
address: wallet.address,
104-
userId,
120+
userId: walletAddress,
105121
} satisfies GetWalletResponse)
106122
} catch (error) {
107123
console.error(error)
@@ -153,13 +169,13 @@ export class WalletController {
153169
*/
154170
async getBalance(c: Context) {
155171
try {
156-
const validation = await validateRequest(c, UserIdParamSchema)
172+
const validation = await validateRequest(c, WalletAddressParamSchema)
157173
if (!validation.success) return validation.response
158174

159175
const {
160-
params: { userId },
176+
params: { walletAddress },
161177
} = validation.data
162-
const balance = await walletService.getBalance(userId)
178+
const balance = await walletService.getBalance(getAddress(walletAddress))
163179

164180
return c.json({ balance: serializeBigInt(balance) })
165181
} catch (error) {
@@ -183,10 +199,10 @@ export class WalletController {
183199
if (!validation.success) return validation.response
184200

185201
const {
186-
params: { userId },
202+
params: { walletAddress },
187203
} = validation.data
188204

189-
const result = await walletService.fundWallet(userId)
205+
const result = await walletService.fundWallet(getAddress(walletAddress))
190206

191207
return c.json(result)
192208
} catch (error) {
@@ -209,11 +225,11 @@ export class WalletController {
209225
if (!validation.success) return validation.response
210226

211227
const {
212-
body: { walletId, amount, recipientAddress },
228+
body: { walletAddress, amount, recipientAddress },
213229
} = validation.data
214230

215231
const transactionData = await walletService.sendTokens(
216-
walletId,
232+
getAddress(walletAddress),
217233
amount,
218234
recipientAddress as Address,
219235
)

packages/demo/backend/src/services/lend.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -58,13 +58,13 @@ export async function getVault(vaultAddress: Address): Promise<LendVaultInfo> {
5858

5959
export async function getVaultBalance(
6060
vaultAddress: Address,
61-
walletId: string,
61+
walletAddress: Address,
6262
): Promise<VaultBalanceResult> {
6363
const verbs = getVerbs()
64-
const wallet = await getWallet(walletId)
64+
const wallet = await getWallet(walletAddress)
6565

6666
if (!wallet) {
67-
throw new Error(`Wallet not found for user ID: ${walletId}`)
67+
throw new Error(`Wallet not found for user ID: ${walletAddress}`)
6868
}
6969

7070
return verbs.lend.getVaultBalance(vaultAddress, wallet.address)
@@ -106,15 +106,15 @@ export async function formatVaultBalanceResponse(
106106
}
107107

108108
export async function deposit(
109-
walletId: string,
109+
walletAddress: Address,
110110
amount: number,
111111
tokenAddress: Address,
112112
chainId: SupportedChainId,
113113
): Promise<LendTransaction> {
114-
const wallet = await getWallet(walletId)
114+
const wallet = await getWallet(walletAddress)
115115

116116
if (!wallet) {
117-
throw new Error(`Wallet not found for user ID: ${walletId}`)
117+
throw new Error(`Wallet not found for user ID: ${walletAddress}`)
118118
}
119119

120120
if ('lendExecute' in wallet && typeof wallet.lendExecute === 'function') {
@@ -127,14 +127,14 @@ export async function deposit(
127127
}
128128

129129
export async function executeLendTransaction(
130-
walletId: string,
130+
walletAddress: Address,
131131
lendTransaction: LendTransaction,
132132
chainId: SupportedChainId,
133133
): Promise<LendTransaction & { blockExplorerUrl: string }> {
134-
const wallet = await getWallet(walletId)
134+
const wallet = await getWallet(walletAddress)
135135

136136
if (!wallet) {
137-
throw new Error(`Wallet not found for user ID: ${walletId}`)
137+
throw new Error(`Wallet not found for user ID: ${walletAddress}`)
138138
}
139139

140140
if (!lendTransaction.transactionData) {

0 commit comments

Comments
 (0)