From 97dacd4604c871974f341e505b96b77abfd4b685 Mon Sep 17 00:00:00 2001 From: its-everdred Date: Mon, 25 Aug 2025 11:14:34 -0700 Subject: [PATCH 1/4] Catch rewards request errors --- packages/sdk/src/lend/providers/morpho/vaults.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/sdk/src/lend/providers/morpho/vaults.ts b/packages/sdk/src/lend/providers/morpho/vaults.ts index e97ea088..80b12460 100644 --- a/packages/sdk/src/lend/providers/morpho/vaults.ts +++ b/packages/sdk/src/lend/providers/morpho/vaults.ts @@ -128,7 +128,15 @@ export async function getVaultInfo( const vault = await fetchAccrualVault(vaultAddress, publicClient) // 3. Fetch rewards data from API - const rewardsBreakdown = await fetchAndCalculateRewards(vaultAddress) + const rewardsBreakdown = await fetchAndCalculateRewards(vaultAddress).catch( + (error) => { + console.error('Failed to fetch rewards data:', error) + return { + other: 0, + totalRewardsApr: 0, + } + }, + ) // 4. Calculate APY breakdown const apyBreakdown = calculateApyBreakdown(vault, rewardsBreakdown) From de66ae008d9fdffa1546cfe8b829c3974b4f1cb7 Mon Sep 17 00:00:00 2001 From: its-everdred Date: Mon, 25 Aug 2025 13:03:10 -0700 Subject: [PATCH 2/4] Switch to Base Sepolia for gas abstraction testing --- packages/demo/backend/src/config/verbs.ts | 8 ++++++-- packages/demo/backend/src/services/lend.ts | 2 +- packages/demo/backend/src/services/wallet.ts | 4 ++-- .../demo/frontend/src/components/Terminal.tsx | 2 +- packages/sdk/src/constants/supportedChains.ts | 9 +++++++-- packages/sdk/src/lend/providers/morpho/index.ts | 9 +++++++-- .../sdk/src/lend/providers/morpho/vaults.ts | 17 ++++++++++++++--- packages/sdk/src/supported/tokens.ts | 4 +++- packages/sdk/src/verbs.ts | 8 ++++---- packages/sdk/src/wallet/providers/privy.ts | 6 +++--- 10 files changed, 48 insertions(+), 21 deletions(-) diff --git a/packages/demo/backend/src/config/verbs.ts b/packages/demo/backend/src/config/verbs.ts index 5d48ac76..145297a7 100644 --- a/packages/demo/backend/src/config/verbs.ts +++ b/packages/demo/backend/src/config/verbs.ts @@ -3,7 +3,7 @@ import { type VerbsConfig, type VerbsInterface, } from '@eth-optimism/verbs-sdk' -import { unichain } from 'viem/chains' +import { baseSepolia, unichain } from 'viem/chains' import { env } from './env.js' @@ -22,7 +22,11 @@ export function createVerbsConfig(): VerbsConfig { chains: [ { chainId: unichain.id, - rpcUrl: env.RPC_URL, + rpcUrl: unichain.rpcUrls.default.http[0], + }, + { + chainId: baseSepolia.id, + rpcUrl: baseSepolia.rpcUrls.default.http[0], }, ], } diff --git a/packages/demo/backend/src/services/lend.ts b/packages/demo/backend/src/services/lend.ts index ef6d3788..dfd400fc 100644 --- a/packages/demo/backend/src/services/lend.ts +++ b/packages/demo/backend/src/services/lend.ts @@ -112,7 +112,7 @@ export async function executeLendTransaction( throw new Error('No transaction data available for execution') } - const publicClient = verbs.chainManager.getPublicClient(130) + const publicClient = verbs.chainManager.getPublicClient(84532) // Base Sepolia const ethBalance = await publicClient.getBalance({ address: wallet.address }) const gasEstimate = await estimateGasCost( diff --git a/packages/demo/backend/src/services/wallet.ts b/packages/demo/backend/src/services/wallet.ts index 57bdf3a1..036a53a6 100644 --- a/packages/demo/backend/src/services/wallet.ts +++ b/packages/demo/backend/src/services/wallet.ts @@ -4,7 +4,7 @@ import type { TransactionData, WalletInterface, } from '@eth-optimism/verbs-sdk' -import { unichain } from '@eth-optimism/viem/chains' +import { baseSepolia, unichain } from '@eth-optimism/viem/chains' import type { Address, Hex } from 'viem' import { createPublicClient, @@ -82,7 +82,7 @@ export async function getBalance(userId: string): Promise { totalFormattedBalance: formattedBalance, chainBalances: [ { - chainId: 130 as const, // Unichain + chainId: 84532 as const, // Base Sepolia balance: vaultBalance.balance, formattedBalance: formattedBalance, }, diff --git a/packages/demo/frontend/src/components/Terminal.tsx b/packages/demo/frontend/src/components/Terminal.tsx index 4f15c690..9a1bdca2 100644 --- a/packages/demo/frontend/src/components/Terminal.tsx +++ b/packages/demo/frontend/src/components/Terminal.tsx @@ -754,7 +754,7 @@ How much would you like to lend?` Vault: ${promptData.selectedVault.name} Amount: ${amount} USDC -Tx: https://uniscan.xyz/tx/${result.transaction.hash || 'pending'}`, +Tx: https://base-sepolia.blockscout.com/tx/${result.transaction.hash || 'pending'}`, timestamp: new Date(), } setLines((prev) => [...prev.slice(0, -1), successLine]) diff --git a/packages/sdk/src/constants/supportedChains.ts b/packages/sdk/src/constants/supportedChains.ts index a0ba0e22..8ed1bb20 100644 --- a/packages/sdk/src/constants/supportedChains.ts +++ b/packages/sdk/src/constants/supportedChains.ts @@ -1,5 +1,10 @@ -import { base, mainnet, unichain } from 'viem/chains' +import { base, baseSepolia, mainnet, unichain } from 'viem/chains' -export const SUPPORTED_CHAIN_IDS = [mainnet.id, unichain.id, base.id] as const +export const SUPPORTED_CHAIN_IDS = [ + mainnet.id, + unichain.id, + base.id, + baseSepolia.id, +] as const export type SupportedChainId = (typeof SUPPORTED_CHAIN_IDS)[number] diff --git a/packages/sdk/src/lend/providers/morpho/index.ts b/packages/sdk/src/lend/providers/morpho/index.ts index c397431b..d73d2737 100644 --- a/packages/sdk/src/lend/providers/morpho/index.ts +++ b/packages/sdk/src/lend/providers/morpho/index.ts @@ -24,6 +24,11 @@ export const SUPPORTED_NETWORKS = { name: 'Unichain', morphoAddress: '0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb' as Address, }, + BASE_SEPOLIA: { + chainId: 84532, + name: 'Base Sepolia', + morphoAddress: '0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb' as Address, // Using same address as Morpho typically uses same deployment address + }, } as const /** @@ -46,8 +51,8 @@ export class LendProviderMorpho extends LendProvider { constructor(config: MorphoLendConfig, publicClient: PublicClient) { super() - // Use Unichain as the default network for now - const network = SUPPORTED_NETWORKS.UNICHAIN + // Use Base Sepolia as the default network for testing + const network = SUPPORTED_NETWORKS.BASE_SEPOLIA this.morphoAddress = network.morphoAddress this.defaultSlippage = config.defaultSlippage || 50 // 0.5% default diff --git a/packages/sdk/src/lend/providers/morpho/vaults.ts b/packages/sdk/src/lend/providers/morpho/vaults.ts index 80b12460..36db4db0 100644 --- a/packages/sdk/src/lend/providers/morpho/vaults.ts +++ b/packages/sdk/src/lend/providers/morpho/vaults.ts @@ -16,13 +16,13 @@ export interface VaultConfig { } /** - * Supported vaults on Unichain for Morpho lending + * Supported vaults for Morpho lending */ export const SUPPORTED_VAULTS: VaultConfig[] = [ { - // Gauntlet USDC vault - primary supported vault + // Gauntlet USDC vault on Unichain address: '0x38f4f3B6533de0023b9DCd04b02F93d36ad1F9f9' as Address, - name: 'Gauntlet USDC', + name: 'Gauntlet USDC (Unichain)', asset: { address: getTokenAddress('USDC', 130)!, // USDC on Unichain symbol: SUPPORTED_TOKENS.USDC.symbol, @@ -30,6 +30,17 @@ export const SUPPORTED_VAULTS: VaultConfig[] = [ name: SUPPORTED_TOKENS.USDC.name, }, }, + { + // USDC vault on Base Sepolia + address: '0x99067e5D73b1d6F1b5856E59209e12F5a0f86DED' as Address, + name: 'USDC Vault (Base Sepolia)', + asset: { + address: '0x036CbD53842c5426634e7929541eC2318f3dCF7e' as Address, // USDC on Base Sepolia + symbol: SUPPORTED_TOKENS.USDC.symbol, + decimals: BigInt(SUPPORTED_TOKENS.USDC.decimals), + name: SUPPORTED_TOKENS.USDC.name, + }, + }, ] /** diff --git a/packages/sdk/src/supported/tokens.ts b/packages/sdk/src/supported/tokens.ts index ffb0a0e3..59e6b29c 100644 --- a/packages/sdk/src/supported/tokens.ts +++ b/packages/sdk/src/supported/tokens.ts @@ -1,5 +1,5 @@ import type { Address } from 'viem' -import { base, mainnet, unichain } from 'viem/chains' +import { base, baseSepolia, mainnet, unichain } from 'viem/chains' import type { SupportedChainId } from '@/constants/supportedChains.js' @@ -19,6 +19,7 @@ export const SUPPORTED_TOKENS: Record = { [mainnet.id]: '0x0000000000000000000000000000000000000000', [unichain.id]: '0x0000000000000000000000000000000000000000', [base.id]: '0x0000000000000000000000000000000000000000', + [baseSepolia.id]: '0x0000000000000000000000000000000000000000', }, }, USDC: { @@ -28,6 +29,7 @@ export const SUPPORTED_TOKENS: Record = { addresses: { [mainnet.id]: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48', [unichain.id]: '0x078d782b760474a361dda0af3839290b0ef57ad6', + [baseSepolia.id]: '0x036CbD53842c5426634e7929541eC2318f3dCF7e', }, }, MORPHO: { diff --git a/packages/sdk/src/verbs.ts b/packages/sdk/src/verbs.ts index 368ceb3a..8ff1733f 100644 --- a/packages/sdk/src/verbs.ts +++ b/packages/sdk/src/verbs.ts @@ -1,5 +1,5 @@ import { createPublicClient, http, type PublicClient } from 'viem' -import { mainnet, unichain } from 'viem/chains' +import { baseSepolia, mainnet, unichain } from 'viem/chains' import { LendProviderMorpho } from '@/lend/index.js' import { ChainManager } from '@/services/ChainManager.js' @@ -39,12 +39,12 @@ export class Verbs implements VerbsInterface { if (config.lend) { // TODO: delete this code and just have the lend use the ChainManager const configChain = config.chains?.[0] - const chainId = configChain?.chainId || 130 // Default to Unichain - const chain = chainId === 130 ? unichain : mainnet + const chainId = configChain?.chainId || 84532 // Default to Base Sepolia + const chain = chainId === 130 ? unichain : chainId === 84532 ? baseSepolia : mainnet const publicClient = createPublicClient({ chain, transport: http( - configChain?.rpcUrl || unichain.rpcUrls.default.http[0], + configChain?.rpcUrl || baseSepolia.rpcUrls.default.http[0], ), }) as PublicClient if (config.lend.type === 'morpho') { diff --git a/packages/sdk/src/wallet/providers/privy.ts b/packages/sdk/src/wallet/providers/privy.ts index 124699f3..9e51b984 100644 --- a/packages/sdk/src/wallet/providers/privy.ts +++ b/packages/sdk/src/wallet/providers/privy.ts @@ -103,12 +103,12 @@ export class WalletProviderPrivy implements WalletProvider { try { const response = await this.privy.walletApi.ethereum.sendTransaction({ walletId, - caip2: 'eip155:130', // Unichain + caip2: 'eip155:84532', // Base Sepolia transaction: { to: transactionData.to, data: transactionData.data as `0x${string}`, value: Number(transactionData.value), - chainId: 130, // Unichain + chainId: 84532, // Base Sepolia }, }) @@ -142,7 +142,7 @@ export class WalletProviderPrivy implements WalletProvider { } // Get public client for gas estimation - const publicClient = this.verbs.chainManager.getPublicClient(130) // Unichain + const publicClient = this.verbs.chainManager.getPublicClient(84532) // Base Sepolia // Estimate gas limit const gasLimit = await publicClient.estimateGas({ From 96713a0dd7a09a2d2a2892bd3700c0e7f251b014 Mon Sep 17 00:00:00 2001 From: its-everdred Date: Mon, 25 Aug 2025 14:41:43 -0700 Subject: [PATCH 3/4] Hard code base-sepolia and update to use sponsored g as --- packages/demo/backend/src/config/verbs.ts | 10 +-- packages/demo/backend/src/controllers/lend.ts | 4 ++ .../demo/backend/src/controllers/wallet.ts | 6 ++ packages/demo/backend/src/services/lend.ts | 16 +++-- packages/demo/backend/src/services/wallet.ts | 2 +- .../src/lend/providers/morpho/index.test.ts | 10 +++ .../sdk/src/lend/providers/morpho/index.ts | 14 ++++- .../sdk/src/lend/providers/morpho/vaults.ts | 53 ++++++++++------ packages/sdk/src/verbs.ts | 13 ++-- packages/sdk/src/wallet/index.ts | 15 +++-- packages/sdk/src/wallet/providers/privy.ts | 63 ++++++++++++++++++- 11 files changed, 160 insertions(+), 46 deletions(-) diff --git a/packages/demo/backend/src/config/verbs.ts b/packages/demo/backend/src/config/verbs.ts index 145297a7..77fcb204 100644 --- a/packages/demo/backend/src/config/verbs.ts +++ b/packages/demo/backend/src/config/verbs.ts @@ -3,7 +3,7 @@ import { type VerbsConfig, type VerbsInterface, } from '@eth-optimism/verbs-sdk' -import { baseSepolia, unichain } from 'viem/chains' +import { baseSepolia } from 'viem/chains' import { env } from './env.js' @@ -20,10 +20,10 @@ export function createVerbsConfig(): VerbsConfig { type: 'morpho', }, chains: [ - { - chainId: unichain.id, - rpcUrl: unichain.rpcUrls.default.http[0], - }, + // { + // chainId: unichain.id, + // rpcUrl: unichain.rpcUrls.default.http[0], + // }, { chainId: baseSepolia.id, rpcUrl: baseSepolia.rpcUrls.default.http[0], diff --git a/packages/demo/backend/src/controllers/lend.ts b/packages/demo/backend/src/controllers/lend.ts index 19cf9903..6a1bcc3e 100644 --- a/packages/demo/backend/src/controllers/lend.ts +++ b/packages/demo/backend/src/controllers/lend.ts @@ -42,6 +42,7 @@ export class LendController { ) return c.json({ vaults: formattedVaults }) } catch (error) { + console.error('[LendController.getVaults] Error:', error) return c.json( { error: 'Failed to get vaults', @@ -67,6 +68,7 @@ export class LendController { const formattedVault = await lendService.formatVaultResponse(vaultInfo) return c.json({ vault: formattedVault }) } catch (error) { + console.error('[LendController.getVault] Error:', error) return c.json( { error: 'Failed to get vault info', @@ -96,6 +98,7 @@ export class LendController { await lendService.formatVaultBalanceResponse(balance) return c.json(formattedBalance) } catch (error) { + console.error('[LendController.getVaultBalance] Error:', error) return c.json( { error: 'Failed to get vault balance', @@ -136,6 +139,7 @@ export class LendController { }, }) } catch (error) { + console.error('[LendController.deposit] Error:', error) return c.json( { error: 'Failed to deposit', diff --git a/packages/demo/backend/src/controllers/wallet.ts b/packages/demo/backend/src/controllers/wallet.ts index 33cdd6c9..bb6f3c1f 100644 --- a/packages/demo/backend/src/controllers/wallet.ts +++ b/packages/demo/backend/src/controllers/wallet.ts @@ -65,6 +65,7 @@ export class WalletController { userId, } satisfies CreateWalletResponse) } catch (error) { + console.error('[WalletController.createWallet] Error:', error) return c.json( { error: 'Failed to create wallet', @@ -103,6 +104,7 @@ export class WalletController { userId, } satisfies GetWalletResponse) } catch (error) { + console.error('[WalletController.getWallet] Error:', error) return c.json( { error: 'Failed to get wallet', @@ -134,6 +136,7 @@ export class WalletController { count: wallets.length, } satisfies GetAllWalletsResponse) } catch (error) { + console.error('[WalletController.getAllWallets] Error:', error) return c.json( { error: 'Failed to get wallets', @@ -159,6 +162,7 @@ export class WalletController { return c.json({ balance: serializeBigInt(balance) }) } catch (error) { + console.error('[WalletController.getBalance] Error:', error) return c.json( { error: 'Failed to get balance', @@ -186,6 +190,7 @@ export class WalletController { return c.json(result) } catch (error) { + console.error('[WalletController.fundWallet] Error:', error) return c.json( { error: 'Failed to fund wallet', @@ -222,6 +227,7 @@ export class WalletController { }, }) } catch (error) { + console.error('[WalletController.sendTokens] Error:', error) return c.json( { error: 'Failed to send tokens', diff --git a/packages/demo/backend/src/services/lend.ts b/packages/demo/backend/src/services/lend.ts index dfd400fc..1d7ebc6b 100644 --- a/packages/demo/backend/src/services/lend.ts +++ b/packages/demo/backend/src/services/lend.ts @@ -121,24 +121,30 @@ export async function executeLendTransaction( lendTransaction, ) + console.log(`[LEND] Gas check - ETH balance: ${ethBalance}, Gas estimate: ${gasEstimate}`) + + // Skip gas check for gas sponsorship testing + // TODO: Add proper gas sponsorship detection if (ethBalance < gasEstimate) { - throw new Error('Insufficient ETH for gas fees') + console.log('[LEND] Insufficient ETH detected, but proceeding with gas sponsorship attempt') + // throw new Error('Insufficient ETH for gas fees') } let depositHash: Address = '0x0' if (lendTransaction.transactionData.approval) { - const approvalSignedTx = await wallet.sign( + console.log('[LEND] Sending approval transaction with potential gas sponsorship') + const approvalHash = await wallet.signAndSend( lendTransaction.transactionData.approval, ) - const approvalHash = await wallet.send(approvalSignedTx, publicClient) + console.log('[LEND] Approval transaction hash:', approvalHash) await publicClient.waitForTransactionReceipt({ hash: approvalHash }) } - const depositSignedTx = await wallet.sign( + console.log('[LEND] Sending deposit transaction with potential gas sponsorship') + depositHash = await wallet.signAndSend( lendTransaction.transactionData.deposit, ) - depositHash = await wallet.send(depositSignedTx, publicClient) await publicClient.waitForTransactionReceipt({ hash: depositHash }) return { ...lendTransaction, hash: depositHash } diff --git a/packages/demo/backend/src/services/wallet.ts b/packages/demo/backend/src/services/wallet.ts index 036a53a6..a5ab2b16 100644 --- a/packages/demo/backend/src/services/wallet.ts +++ b/packages/demo/backend/src/services/wallet.ts @@ -4,7 +4,7 @@ import type { TransactionData, WalletInterface, } from '@eth-optimism/verbs-sdk' -import { baseSepolia, unichain } from '@eth-optimism/viem/chains' +import { unichain } from '@eth-optimism/viem/chains' import type { Address, Hex } from 'viem' import { createPublicClient, diff --git a/packages/sdk/src/lend/providers/morpho/index.test.ts b/packages/sdk/src/lend/providers/morpho/index.test.ts index ebaf79c4..8b10bc56 100644 --- a/packages/sdk/src/lend/providers/morpho/index.test.ts +++ b/packages/sdk/src/lend/providers/morpho/index.test.ts @@ -58,9 +58,14 @@ describe('LendProviderMorpho', () => { transport: http(), }) + const mockChainManager = { + getPublicClient: () => mockPublicClient, + } as any + provider = new LendProviderMorpho( mockConfig, mockPublicClient as unknown as PublicClient, + mockChainManager, ) }) @@ -74,9 +79,14 @@ describe('LendProviderMorpho', () => { ...mockConfig, defaultSlippage: undefined, } + const mockChainManager = { + getPublicClient: () => mockPublicClient, + } as any + const providerWithDefaults = new LendProviderMorpho( configWithoutSlippage, mockPublicClient as unknown as PublicClient, + mockChainManager, ) expect(providerWithDefaults).toBeInstanceOf(LendProviderMorpho) }) diff --git a/packages/sdk/src/lend/providers/morpho/index.ts b/packages/sdk/src/lend/providers/morpho/index.ts index d73d2737..5db78083 100644 --- a/packages/sdk/src/lend/providers/morpho/index.ts +++ b/packages/sdk/src/lend/providers/morpho/index.ts @@ -2,6 +2,7 @@ import { MetaMorphoAction } from '@morpho-org/blue-sdk-viem' import type { Address, PublicClient } from 'viem' import { encodeFunctionData, erc20Abi, formatUnits } from 'viem' +import type { ChainManager } from '../../../services/ChainManager.js' import type { LendOptions, LendTransaction, @@ -42,13 +43,19 @@ export class LendProviderMorpho extends LendProvider { private morphoAddress: Address private defaultSlippage: number private publicClient: PublicClient + private chainManager: ChainManager /** * Create a new Morpho lending provider * @param config - Morpho lending configuration * @param publicClient - Viem public client for blockchain interactions // TODO: remove this + * @param chainManager - Chain manager for multi-chain support */ - constructor(config: MorphoLendConfig, publicClient: PublicClient) { + constructor( + config: MorphoLendConfig, + publicClient: PublicClient, + chainManager: ChainManager, + ) { super() // Use Base Sepolia as the default network for testing @@ -57,6 +64,7 @@ export class LendProviderMorpho extends LendProvider { this.morphoAddress = network.morphoAddress this.defaultSlippage = config.defaultSlippage || 50 // 0.5% default this.publicClient = publicClient + this.chainManager = chainManager } /** @@ -177,7 +185,7 @@ export class LendProviderMorpho extends LendProvider { * @returns Promise resolving to vault information */ async getVault(vaultAddress: Address): Promise { - return getVaultInfoHelper(vaultAddress, this.publicClient) + return getVaultInfoHelper(vaultAddress, this.chainManager) } /** @@ -185,7 +193,7 @@ export class LendProviderMorpho extends LendProvider { * @returns Promise resolving to array of vault information */ async getVaults(): Promise { - return getVaultsHelper(this.publicClient) + return getVaultsHelper(this.chainManager) } /** diff --git a/packages/sdk/src/lend/providers/morpho/vaults.ts b/packages/sdk/src/lend/providers/morpho/vaults.ts index 36db4db0..80472515 100644 --- a/packages/sdk/src/lend/providers/morpho/vaults.ts +++ b/packages/sdk/src/lend/providers/morpho/vaults.ts @@ -1,8 +1,10 @@ import type { AccrualPosition, IToken } from '@morpho-org/blue-sdk' import { fetchAccrualVault } from '@morpho-org/blue-sdk-viem' -import type { Address, PublicClient } from 'viem' +import type { Address } from 'viem' -import { getTokenAddress, SUPPORTED_TOKENS } from '../../../supported/tokens.js' +import type { SupportedChainId } from '../../../constants/supportedChains.js' +import type { ChainManager } from '../../../services/ChainManager.js' +import { SUPPORTED_TOKENS } from '../../../supported/tokens.js' import type { ApyBreakdown, LendVaultInfo } from '../../../types/lend.js' import { fetchRewards, type RewardsBreakdown } from './api.js' @@ -13,23 +15,24 @@ export interface VaultConfig { address: Address name: string asset: IToken & { address: Address } + chainId: SupportedChainId } /** * Supported vaults for Morpho lending */ export const SUPPORTED_VAULTS: VaultConfig[] = [ - { - // Gauntlet USDC vault on Unichain - address: '0x38f4f3B6533de0023b9DCd04b02F93d36ad1F9f9' as Address, - name: 'Gauntlet USDC (Unichain)', - asset: { - address: getTokenAddress('USDC', 130)!, // USDC on Unichain - symbol: SUPPORTED_TOKENS.USDC.symbol, - decimals: BigInt(SUPPORTED_TOKENS.USDC.decimals), - name: SUPPORTED_TOKENS.USDC.name, - }, - }, + // { + // // Gauntlet USDC vault on Unichain + // address: '0x38f4f3B6533de0023b9DCd04b02F93d36ad1F9f9' as Address, + // name: 'Gauntlet USDC (Unichain)', + // asset: { + // address: getTokenAddress('USDC', 130)!, // USDC on Unichain + // symbol: SUPPORTED_TOKENS.USDC.symbol, + // decimals: BigInt(SUPPORTED_TOKENS.USDC.decimals), + // name: SUPPORTED_TOKENS.USDC.name, + // }, + // }, { // USDC vault on Base Sepolia address: '0x99067e5D73b1d6F1b5856E59209e12F5a0f86DED' as Address, @@ -40,6 +43,7 @@ export const SUPPORTED_VAULTS: VaultConfig[] = [ decimals: BigInt(SUPPORTED_TOKENS.USDC.decimals), name: SUPPORTED_TOKENS.USDC.name, }, + chainId: 84532 as SupportedChainId, // Base Sepolia }, ] @@ -120,12 +124,12 @@ export function calculateBaseApy(vault: any): number { /** * Get detailed vault information with enhanced rewards data * @param vaultAddress - Vault address - * @param publicClient - Viem public client + * @param chainManager - Chain manager for multi-chain support * @returns Promise resolving to detailed vault information */ export async function getVaultInfo( vaultAddress: Address, - publicClient: PublicClient, + chainManager: ChainManager, ): Promise { try { // 1. Find vault configuration for validation @@ -136,7 +140,18 @@ export async function getVaultInfo( } // 2. Fetch live vault data from Morpho SDK - const vault = await fetchAccrualVault(vaultAddress, publicClient) + const vault = await fetchAccrualVault( + vaultAddress, + chainManager.getPublicClient(config.chainId), + ).catch((error) => { + console.error('Failed to fetch vault info:', error) + return { + totalAssets: 0n, + totalSupply: 0n, + owner: '0x' as Address, + curator: '0x' as Address, + } + }) // 3. Fetch rewards data from API const rewardsBreakdown = await fetchAndCalculateRewards(vaultAddress).catch( @@ -179,15 +194,15 @@ export async function getVaultInfo( /** * Get list of available vaults - * @param publicClient - Viem public client + * @param chainManager - Chain manager for multi-chain support * @returns Promise resolving to array of vault information */ export async function getVaults( - publicClient: PublicClient, + chainManager: ChainManager, ): Promise { try { const vaultInfoPromises = SUPPORTED_VAULTS.map((config) => - getVaultInfo(config.address, publicClient), + getVaultInfo(config.address, chainManager), ) return await Promise.all(vaultInfoPromises) } catch (error) { diff --git a/packages/sdk/src/verbs.ts b/packages/sdk/src/verbs.ts index 8ff1733f..a48402f0 100644 --- a/packages/sdk/src/verbs.ts +++ b/packages/sdk/src/verbs.ts @@ -30,8 +30,8 @@ export class Verbs implements VerbsInterface { this._chainManager = new ChainManager( config.chains || [ { - chainId: unichain.id, - rpcUrl: unichain.rpcUrls.default.http[0], + chainId: baseSepolia.id, + rpcUrl: baseSepolia.rpcUrls.default.http[0], }, ], ) @@ -40,7 +40,8 @@ export class Verbs implements VerbsInterface { // TODO: delete this code and just have the lend use the ChainManager const configChain = config.chains?.[0] const chainId = configChain?.chainId || 84532 // Default to Base Sepolia - const chain = chainId === 130 ? unichain : chainId === 84532 ? baseSepolia : mainnet + const chain = + chainId === 130 ? unichain : chainId === 84532 ? baseSepolia : mainnet const publicClient = createPublicClient({ chain, transport: http( @@ -48,7 +49,11 @@ export class Verbs implements VerbsInterface { ), }) as PublicClient if (config.lend.type === 'morpho') { - this.lendProvider = new LendProviderMorpho(config.lend, publicClient) + this.lendProvider = new LendProviderMorpho( + config.lend, + publicClient, + this._chainManager, + ) } else { throw new Error( `Unsupported lending provider type: ${config.lend.type}`, diff --git a/packages/sdk/src/wallet/index.ts b/packages/sdk/src/wallet/index.ts index 96e0a715..d4a7500b 100644 --- a/packages/sdk/src/wallet/index.ts +++ b/packages/sdk/src/wallet/index.ts @@ -1,5 +1,4 @@ import { type Address, encodeFunctionData, erc20Abi, type Hash } from 'viem' -import { unichain } from 'viem/chains' import { fetchERC20Balance, fetchETHBalance } from '@/services/tokenBalance.js' import { SUPPORTED_TOKENS } from '@/supported/tokens.js' @@ -90,11 +89,11 @@ export class Wallet implements WalletInterface { } // Parse human-readable inputs - // TODO: Get actual chain ID from wallet context, for now using Unichain + // TODO: Get actual chain ID from wallet context, for now using Base Sepolia const { amount: parsedAmount, asset: resolvedAsset } = parseLendParams( amount, asset, - unichain.id, + 84532, // Base Sepolia ) // Set receiver to wallet address if not specified @@ -125,11 +124,11 @@ export class Wallet implements WalletInterface { throw new Error('Wallet not initialized') } - if (!this.walletProvider || !this.walletProvider.sign) { - throw new Error('Wallet provider does not support transaction signing') + if (!this.walletProvider || !(this.walletProvider as any).signAndSend) { + throw new Error('Wallet provider does not support signAndSend') } - return this.walletProvider.sign(this.id, transactionData) + return (this.walletProvider as any).signAndSend(this.id, transactionData) } /** @@ -205,8 +204,8 @@ export class Wallet implements WalletInterface { throw new Error('Amount must be greater than 0') } - // TODO: Get actual chain ID from wallet context, for now using Unichain - const chainId = unichain.id + // TODO: Get actual chain ID from wallet context, for now using Base Sepolia + const chainId = 84532 // Base Sepolia // Handle ETH transfers if (asset.toLowerCase() === 'eth') { diff --git a/packages/sdk/src/wallet/providers/privy.ts b/packages/sdk/src/wallet/providers/privy.ts index 9e51b984..473f59ac 100644 --- a/packages/sdk/src/wallet/providers/privy.ts +++ b/packages/sdk/src/wallet/providers/privy.ts @@ -122,6 +122,67 @@ export class WalletProviderPrivy implements WalletProvider { } } + /** + * Sign and send a transaction with gas sponsorship support + * @description Signs and sends a transaction using Privy's RPC API with gas sponsorship + * @param walletId - Wallet identifier + * @param transactionData - Transaction data to sign and send + * @returns Promise resolving to transaction hash + * @throws Error if transaction signing fails + */ + async signAndSend( + walletId: string, + transactionData: TransactionData, + ): Promise { + try { + // Try using the rpc method directly for gas sponsorship + const rpcPayload = { + method: 'eth_sendTransaction', + caip2: 'eip155:84532', + params: { + transaction: { + to: transactionData.to, + data: transactionData.data, + value: transactionData.value, + }, + }, + sponsor: true, + } + + // Check if rpc method exists on walletApi + if ('rpc' in this.privy.walletApi && typeof this.privy.walletApi.rpc === 'function') { + console.log('[PRIVY] Using RPC method with gas sponsorship') + const response = await (this.privy.walletApi as any).rpc({ + walletId, + ...rpcPayload, + }) + console.log('[PRIVY] RPC response:', JSON.stringify(response, null, 2)) + return response.data.hash as Hash + } + + // Fallback to regular sendTransaction if rpc method not available + console.log('[PRIVY] Using regular sendTransaction method (no gas sponsorship)') + const response = await this.privy.walletApi.ethereum.sendTransaction({ + walletId, + caip2: 'eip155:84532', // Base Sepolia + transaction: { + to: transactionData.to, + data: transactionData.data as `0x${string}`, + value: Number(transactionData.value), + chainId: 84532, // Base Sepolia + }, + }) + + return response.hash as Hash + } catch (error) { + throw new Error( + `Failed to sign and send transaction for wallet ${walletId}: ${ + error instanceof Error ? error.message : 'Unknown error' + }`, + ) + } + } + /** * Sign a transaction without sending it * @description Signs a transaction using Privy's wallet API but doesn't send it @@ -166,7 +227,7 @@ export class WalletProviderPrivy implements WalletProvider { to: transactionData.to, data: transactionData.data as `0x${string}`, value: transactionData.value as `0x${string}`, - chainId: 130, // Unichain + chainId: 84532, // Base Sepolia type: 2, // EIP-1559 gasLimit: `0x${gasLimit.toString(16)}`, maxFeePerGas: `0x${(feeData.maxFeePerGas || BigInt(1000000000)).toString(16)}`, // fallback to 1 gwei From c4c59a9fafbcd205381b4a411e3765c4de5cbee0 Mon Sep 17 00:00:00 2001 From: its-everdred Date: Mon, 25 Aug 2025 14:43:26 -0700 Subject: [PATCH 4/4] Remove debug logs --- packages/demo/backend/src/services/lend.ts | 9 ++------- packages/sdk/src/wallet/providers/privy.ts | 8 +------- 2 files changed, 3 insertions(+), 14 deletions(-) diff --git a/packages/demo/backend/src/services/lend.ts b/packages/demo/backend/src/services/lend.ts index 1d7ebc6b..7ab8cabd 100644 --- a/packages/demo/backend/src/services/lend.ts +++ b/packages/demo/backend/src/services/lend.ts @@ -121,27 +121,22 @@ export async function executeLendTransaction( lendTransaction, ) - console.log(`[LEND] Gas check - ETH balance: ${ethBalance}, Gas estimate: ${gasEstimate}`) - - // Skip gas check for gas sponsorship testing + // Skip gas check when using gas sponsorship // TODO: Add proper gas sponsorship detection if (ethBalance < gasEstimate) { - console.log('[LEND] Insufficient ETH detected, but proceeding with gas sponsorship attempt') + // Proceed with gas sponsorship - Privy will handle gas fees // throw new Error('Insufficient ETH for gas fees') } let depositHash: Address = '0x0' if (lendTransaction.transactionData.approval) { - console.log('[LEND] Sending approval transaction with potential gas sponsorship') const approvalHash = await wallet.signAndSend( lendTransaction.transactionData.approval, ) - console.log('[LEND] Approval transaction hash:', approvalHash) await publicClient.waitForTransactionReceipt({ hash: approvalHash }) } - console.log('[LEND] Sending deposit transaction with potential gas sponsorship') depositHash = await wallet.signAndSend( lendTransaction.transactionData.deposit, ) diff --git a/packages/sdk/src/wallet/providers/privy.ts b/packages/sdk/src/wallet/providers/privy.ts index 473f59ac..2355f5f4 100644 --- a/packages/sdk/src/wallet/providers/privy.ts +++ b/packages/sdk/src/wallet/providers/privy.ts @@ -149,19 +149,16 @@ export class WalletProviderPrivy implements WalletProvider { sponsor: true, } - // Check if rpc method exists on walletApi + // Check if rpc method exists on walletApi for gas sponsorship if ('rpc' in this.privy.walletApi && typeof this.privy.walletApi.rpc === 'function') { - console.log('[PRIVY] Using RPC method with gas sponsorship') const response = await (this.privy.walletApi as any).rpc({ walletId, ...rpcPayload, }) - console.log('[PRIVY] RPC response:', JSON.stringify(response, null, 2)) return response.data.hash as Hash } // Fallback to regular sendTransaction if rpc method not available - console.log('[PRIVY] Using regular sendTransaction method (no gas sponsorship)') const response = await this.privy.walletApi.ethereum.sendTransaction({ walletId, caip2: 'eip155:84532', // Base Sepolia @@ -235,9 +232,6 @@ export class WalletProviderPrivy implements WalletProvider { nonce: `0x${nonce.toString(16)}`, // Explicitly provide the correct nonce } - console.log( - `[PRIVY_PROVIDER] Complete tx params - Type: ${txParams.type}, Nonce: ${nonce}, Limit: ${gasLimit}, MaxFee: ${feeData.maxFeePerGas || 'fallback'}, Priority: ${feeData.maxPriorityFeePerGas || 'fallback'}`, - ) const response = await this.privy.walletApi.ethereum.signTransaction({ walletId,