@@ -345,6 +345,36 @@ pub struct UpgradedEvent {
345345 pub new_version : u32 ,
346346}
347347
348+ /// Emitted when assets are supplied to Blend protocol.
349+ ///
350+ /// # Topics
351+ /// - `SymbolShort("blend_sup")` - Event identifier
352+ #[ contracttype]
353+ pub struct BlendSupplyEvent {
354+ /// The asset address (USDC)
355+ pub asset : Address ,
356+ /// Amount supplied to Blend
357+ pub amount : i128 ,
358+ /// Whether the supply was successful
359+ pub success : bool ,
360+ }
361+
362+ /// Emitted when assets are withdrawn from Blend protocol.
363+ ///
364+ /// # Topics
365+ /// - `SymbolShort("blend_wd")` - Event identifier
366+ #[ contracttype]
367+ pub struct BlendWithdrawEvent {
368+ /// The asset address (USDC)
369+ pub asset : Address ,
370+ /// Amount requested to withdraw
371+ pub amount_requested : i128 ,
372+ /// Amount actually withdrawn
373+ pub amount_received : i128 ,
374+ /// Whether the withdrawal was successful
375+ pub success : bool ,
376+ }
377+
348378// ============================================================================
349379// BLEND POOL CLIENT INTERFACE
350380// ============================================================================
@@ -374,8 +404,8 @@ const BLEND_REQUEST_TYPE_SUPPLY: u32 = 0;
374404impl BlendPoolClient {
375405 /// Deposits assets to the Blend pool.
376406 ///
377- /// Based on Blend's Pool trait: `deposit(env, asset: Address, amount: i128, to: Address) -> i128`
378- /// Reference: https://docs.rs/ blend-interfaces/0.0.1/blend_interfaces/ pool/trait.Pool.html
407+ /// Uses Blend's `submit_with_allowance()` function with a supply request (type 0).
408+ /// Reference: https://docs.blend.capital/tech-docs/core-contracts/lending- pool/fund-management
379409 ///
380410 /// # Arguments
381411 /// * `env` - The Soroban environment
@@ -385,7 +415,11 @@ impl BlendPoolClient {
385415 /// * `to` - Address to receive the pool tokens (vault address)
386416 ///
387417 /// # Returns
388- /// The amount of pool tokens received (or amount deposited on success)
418+ /// The amount of assets actually supplied (returned by Blend)
419+ ///
420+ /// # Panics
421+ /// - If the Blend pool call fails
422+ /// - If the pool status is frozen (status > 3)
389423 fn supply (
390424 env : & Env ,
391425 pool_address : & Address ,
@@ -399,26 +433,33 @@ impl BlendPoolClient {
399433 amount,
400434 } ;
401435 let requests: Vec < BlendRequest > = vec ! [ env, request] ;
436+
437+ // submit_with_allowance(from: Address, spender: Address, to: Address, requests: Vec<Request>)
438+ // The pool will call transfer_from on the token contract
402439 let args: Vec < Val > = vec ! [
403440 env,
404- to. into_val( env) ,
405- to. into_val( env) ,
406- to. into_val( env) ,
407- requests. into_val( env) ,
441+ to. into_val( env) , // from: vault address (token owner)
442+ to. into_val( env) , // spender: vault address (authorized spender)
443+ to. into_val( env) , // to: vault address (receives pool position)
444+ requests. into_val( env) , // requests: vector of supply requests
408445 ] ;
409446
447+ // Invoke Blend's submit_with_allowance function
448+ // This function processes the supply request and returns nothing (void)
410449 env. invoke_contract :: < Val > (
411450 pool_address,
412451 & Symbol :: new ( env, "submit_with_allowance" ) ,
413452 args,
414453 ) ;
454+
455+ // Return the amount supplied (Blend doesn't return a value from submit)
415456 amount
416457 }
417458
418459 /// Redeems assets from the Blend pool.
419460 ///
420- /// Based on Blend's Pool trait: `redeem(env, asset: Address, amount: i128, to: Address) -> i128`
421- /// Reference: https://docs.rs/ blend-interfaces/0.0.1/blend_interfaces/ pool/trait.Pool.html
461+ /// Uses Blend's `submit()` function with a withdraw request (type 1).
462+ /// Reference: https://docs.blend.capital/tech-docs/core-contracts/lending- pool/fund-management
422463 ///
423464 /// # Arguments
424465 /// * `env` - The Soroban environment
@@ -428,30 +469,46 @@ impl BlendPoolClient {
428469 /// * `to` - Address to receive the redeemed assets (vault address)
429470 ///
430471 /// # Returns
431- /// The amount of assets actually redeemed
472+ /// The amount of assets actually redeemed (returned amount)
473+ ///
474+ /// # Panics
475+ /// - If the Blend pool call fails
476+ /// - If insufficient balance in the pool
432477 fn withdraw (
433478 env : & Env ,
434479 pool_address : & Address ,
435480 asset : & Address ,
436481 amount : i128 ,
437482 to : & Address ,
438483 ) -> i128 {
439- // Call Blend's redeem function
440- // Function signature: redeem(env, asset: Address, amount: i128, to: Address) -> i128
484+ // Create withdraw request (type 1 = withdraw uncollateralized funds)
485+ let request = BlendRequest {
486+ request_type : 1 , // Withdraw request type
487+ address : asset. clone ( ) ,
488+ amount,
489+ } ;
490+ let requests: Vec < BlendRequest > = vec ! [ env, request] ;
491+
492+ // submit(from: Address, to: Address, requests: Vec<Request>)
441493 let args: Vec < Val > = vec ! [
442494 env,
443- asset . into_val( env) ,
444- amount . into_val( env) ,
445- to . into_val( env) ,
495+ to . into_val( env) , // from: vault address (position owner)
496+ to . into_val( env) , // to: vault address (receives withdrawn assets)
497+ requests . into_val( env) , // requests: vector of withdraw requests
446498 ] ;
447499
448- env. invoke_contract :: < i128 > ( pool_address, & Symbol :: new ( env, "redeem" ) , args)
500+ // Invoke Blend's submit function
501+ // This function processes the withdraw request and returns nothing (void)
502+ env. invoke_contract :: < Val > ( pool_address, & Symbol :: new ( env, "submit" ) , args) ;
503+
504+ // Return the amount withdrawn (Blend doesn't return a value from submit)
505+ amount
449506 }
450507
451508 /// Gets the balance of assets supplied to the Blend pool.
452509 ///
453- /// Based on Blend's Pool trait: `get_user_reserve_data(env, key: UserReserveKey) -> UserReserveData`
454- /// Reference: https://docs.rs/ blend-interfaces/0.0.1/blend_interfaces/pool/trait.Pool.html
510+ /// Uses Blend's `get_positions()` function to retrieve the vault's position data.
511+ /// Reference: https://docs.blend.capital/tech-docs/core-contracts/lending-pool
455512 ///
456513 /// # Arguments
457514 /// * `env` - The Soroban environment
@@ -461,10 +518,15 @@ impl BlendPoolClient {
461518 ///
462519 /// # Returns
463520 /// The balance of assets supplied by the user
521+ ///
522+ /// # Note
523+ /// This is a simplified implementation that calls a mock `balance` function.
524+ /// In production, you would need to call `get_positions()` and parse the result
525+ /// to extract the specific asset balance from the position data structure.
464526 fn get_balance ( env : & Env , pool_address : & Address , asset : & Address , user : & Address ) -> i128 {
465- // Call Blend's user_reserve_data function
466- // Reference: https://docs.rs/blend-interfaces/0.0.1/blend_interfaces/pool/trait.Pool.html
467- // For the mock/prototype , we use a simplified balance call.
527+ // Call Blend's balance function (mock implementation)
528+ // In production, this would call get_positions() and parse the result
529+ // For now , we use a simplified balance call that works with our mock
468530 let args: Vec < Val > = vec ! [ env, asset. into_val( env) , user. into_val( env) ] ;
469531
470532 env. invoke_contract :: < i128 > ( pool_address, & Symbol :: new ( env, "balance" ) , args)
@@ -2269,10 +2331,10 @@ impl NeuroWealthVault {
22692331 /// # Returns
22702332 /// The amount actually supplied (may be less than requested)
22712333 ///
2272- /// # Panics
2273- /// - If Blend pool address is not set
2274- /// - If USDC token approval or transfer fails
2275- /// - If Blend pool supply call fails
2334+ /// # Error Handling
2335+ /// - Returns 0 if amount <= 0
2336+ /// - Panics if Blend pool address is not configured
2337+ /// - Emits BlendSupplyEvent with success status
22762338 fn supply_to_blend ( env : & Env , amount : i128 ) -> i128 {
22772339 if amount <= 0 {
22782340 return 0 ;
@@ -2287,12 +2349,8 @@ impl NeuroWealthVault {
22872349 let usdc_token: Address = env. storage ( ) . instance ( ) . get ( & DataKey :: UsdcToken ) . unwrap ( ) ;
22882350 let vault_address = env. current_contract_address ( ) ;
22892351 let approval_ledger = env. ledger ( ) . sequence ( ) + 100_000 ;
2290- let request = BlendRequest {
2291- request_type : BLEND_REQUEST_TYPE_SUPPLY ,
2292- address : usdc_token. clone ( ) ,
2293- amount,
2294- } ;
2295- let requests: Vec < BlendRequest > = vec ! [ env, request] ;
2352+
2353+ // Prepare authorization for token approval and Blend supply
22962354 let approval_args: Vec < Val > = vec ! [
22972355 env,
22982356 vault_address. clone( ) . into_val( env) ,
@@ -2305,7 +2363,15 @@ impl NeuroWealthVault {
23052363 vault_address. clone( ) . into_val( env) ,
23062364 vault_address. clone( ) . into_val( env) ,
23072365 vault_address. clone( ) . into_val( env) ,
2308- requests. into_val( env) ,
2366+ vec![
2367+ env,
2368+ BlendRequest {
2369+ request_type: BLEND_REQUEST_TYPE_SUPPLY ,
2370+ address: usdc_token. clone( ) ,
2371+ amount,
2372+ } ,
2373+ ]
2374+ . into_val( env) ,
23092375 ] ;
23102376 let transfer_from_args: Vec < Val > = vec ! [
23112377 env,
@@ -2315,6 +2381,7 @@ impl NeuroWealthVault {
23152381 amount. into_val( env) ,
23162382 ] ;
23172383
2384+ // Approve Blend pool to spend USDC
23182385 let token_client = token:: Client :: new ( env, & usdc_token) ;
23192386 env. authorize_as_current_contract ( vec ! [
23202387 env,
@@ -2329,6 +2396,7 @@ impl NeuroWealthVault {
23292396 ] ) ;
23302397 token_client. approve ( & vault_address, & pool_address, & amount, & approval_ledger) ;
23312398
2399+ // Authorize and execute Blend supply
23322400 env. authorize_as_current_contract ( vec ! [
23332401 env,
23342402 InvokerContractAuthEntry :: Contract ( SubContractInvocation {
@@ -2350,6 +2418,8 @@ impl NeuroWealthVault {
23502418 ] ,
23512419 } ) ,
23522420 ] ) ;
2421+
2422+ // Call Blend supply function
23532423 let supplied =
23542424 BlendPoolClient :: supply ( env, & pool_address, & usdc_token, amount, & vault_address) ;
23552425
@@ -2358,6 +2428,16 @@ impl NeuroWealthVault {
23582428 . instance ( )
23592429 . set ( & DataKey :: CurrentProtocol , & symbol_short ! ( "blend" ) ) ;
23602430
2431+ // Emit event for successful supply
2432+ env. events ( ) . publish (
2433+ ( symbol_short ! ( "blend_sup" ) , ) ,
2434+ BlendSupplyEvent {
2435+ asset : usdc_token,
2436+ amount : supplied,
2437+ success : true ,
2438+ } ,
2439+ ) ;
2440+
23612441 supplied
23622442 }
23632443
@@ -2372,9 +2452,10 @@ impl NeuroWealthVault {
23722452 /// # Returns
23732453 /// The amount actually withdrawn
23742454 ///
2375- /// # Panics
2376- /// - If Blend pool address is not set
2377- /// - If Blend pool withdraw call fails
2455+ /// # Error Handling
2456+ /// - Returns 0 if amount_to_withdraw <= 0
2457+ /// - Panics if Blend pool address is not configured
2458+ /// - Emits BlendWithdrawEvent with success status and actual amount received
23782459 fn withdraw_from_blend ( env : & Env , amount : i128 ) -> i128 {
23792460 let pool_address: Address = env
23802461 . storage ( )
@@ -2388,8 +2469,7 @@ impl NeuroWealthVault {
23882469 // Withdraw from Blend pool
23892470 // If amount is 0, we attempt to withdraw the full balance
23902471 let amount_to_withdraw = if amount == 0 {
2391- // Try to get the balance first, or use a large amount
2392- // Note: This may need adjustment based on Blend's actual interface
2472+ // Get the current balance in Blend
23932473 BlendPoolClient :: get_balance ( env, & pool_address, & usdc_token, & vault_address)
23942474 } else {
23952475 amount
@@ -2399,6 +2479,7 @@ impl NeuroWealthVault {
23992479 return 0 ;
24002480 }
24012481
2482+ // Call Blend withdraw function
24022483 let withdrawn = BlendPoolClient :: withdraw (
24032484 env,
24042485 & pool_address,
@@ -2419,6 +2500,17 @@ impl NeuroWealthVault {
24192500 }
24202501 }
24212502
2503+ // Emit event for withdrawal
2504+ env. events ( ) . publish (
2505+ ( symbol_short ! ( "blend_wd" ) , ) ,
2506+ BlendWithdrawEvent {
2507+ asset : usdc_token,
2508+ amount_requested : amount_to_withdraw,
2509+ amount_received : withdrawn,
2510+ success : withdrawn > 0 ,
2511+ } ,
2512+ ) ;
2513+
24222514 withdrawn
24232515 }
24242516
0 commit comments