package v1 import ( "chain/runtime" prbac "gno.land/p/gnoswap/rbac" u256 "gno.land/p/gnoswap/uint256" "gno.land/r/gnoswap/access" "gno.land/r/gnoswap/common" "gno.land/r/gnoswap/halt" ) // SwapCallback implements the pool's SwapCallback interface. // This is called by the pool after it has sent output tokens to the recipient. // The router must transfer the required input tokens to the pool. // // This callback pattern enables: // 1. Flash swaps (receive tokens before paying) // 2. Just-in-time token transfers // 3. Complex multi-hop swaps without intermediate transfers // // Parameters: // - token0Path, token1Path: Pool token paths // - amount0Delta, amount1Delta: Token deltas (positive = owe, negative = received) // - payer: Address that will pay for the swap // // Access: // - Only callable by Router v1 address (self-callback from pool) // // Returns: // - error: nil on success, error if transfer fails // // Delta convention (Uniswap V3): // - Positive delta: tokens the pool must receive (input token) // - Negative delta: tokens the pool has sent (output token) func (r *routerV1) SwapCallback( token0Path, token1Path string, amount0Delta, amount1Delta int64, payer address, ) error { halt.AssertIsNotHaltedRouter() caller := runtime.PreviousRealm().Address() assertIsRouterV1(caller) var tokenToPay string var amountToPay int64 // amount0Delta > 0 means pool wants token0 // amount1Delta > 0 means pool wants token1 if amount0Delta > 0 { amountToPay = amount0Delta tokenToPay = token0Path } else if amount1Delta > 0 { amountToPay = amount1Delta tokenToPay = token1Path } else { return nil } // Transfer tokens from router to pool // The router should already have the tokens from the user r.transferToPool(tokenToPay, u256.NewUintFromInt64(amountToPay), payer) return nil } // transferToPool transfers tokens from router to pool func (r *routerV1) transferToPool(token string, amount *u256.Uint, payer address) { balance := common.BalanceOf(token, payer) if u256.NewUintFromInt64(balance).Lt(amount) { panic("insufficient balance in router for callback") } poolAddr := access.MustGetAddress(prbac.ROLE_POOL.String()) routerAddr := access.MustGetAddress(prbac.ROLE_ROUTER.String()) if payer == routerAddr { common.SafeGRC20Transfer(cross, token, poolAddr, amount.Int64()) } else { common.SafeGRC20TransferFrom(cross, token, payer, poolAddr, amount.Int64()) } }