swap_callback.gno
2.40 Kb ยท 85 lines
1package v1
2
3import (
4 "chain/runtime"
5
6 prbac "gno.land/p/gnoswap/rbac"
7 u256 "gno.land/p/gnoswap/uint256"
8
9 "gno.land/r/gnoswap/access"
10 "gno.land/r/gnoswap/common"
11 "gno.land/r/gnoswap/halt"
12)
13
14// SwapCallback implements the pool's SwapCallback interface.
15// This is called by the pool after it has sent output tokens to the recipient.
16// The router must transfer the required input tokens to the pool.
17//
18// This callback pattern enables:
19// 1. Flash swaps (receive tokens before paying)
20// 2. Just-in-time token transfers
21// 3. Complex multi-hop swaps without intermediate transfers
22//
23// Parameters:
24// - token0Path, token1Path: Pool token paths
25// - amount0Delta, amount1Delta: Token deltas (positive = owe, negative = received)
26// - payer: Address that will pay for the swap
27//
28// Access:
29// - Only callable by Router v1 address (self-callback from pool)
30//
31// Returns:
32// - error: nil on success, error if transfer fails
33//
34// Delta convention (Uniswap V3):
35// - Positive delta: tokens the pool must receive (input token)
36// - Negative delta: tokens the pool has sent (output token)
37func (r *routerV1) SwapCallback(
38 token0Path, token1Path string,
39 amount0Delta, amount1Delta int64,
40 payer address,
41) error {
42 halt.AssertIsNotHaltedRouter()
43
44 caller := runtime.PreviousRealm().Address()
45 assertIsRouterV1(caller)
46
47 var tokenToPay string
48 var amountToPay int64
49
50 // amount0Delta > 0 means pool wants token0
51 // amount1Delta > 0 means pool wants token1
52 if amount0Delta > 0 {
53 amountToPay = amount0Delta
54 tokenToPay = token0Path
55 } else if amount1Delta > 0 {
56 amountToPay = amount1Delta
57 tokenToPay = token1Path
58 } else {
59 return nil
60 }
61
62 // Transfer tokens from router to pool
63 // The router should already have the tokens from the user
64 r.transferToPool(tokenToPay, u256.NewUintFromInt64(amountToPay), payer)
65
66 return nil
67}
68
69// transferToPool transfers tokens from router to pool
70func (r *routerV1) transferToPool(token string, amount *u256.Uint, payer address) {
71 balance := common.BalanceOf(token, payer)
72
73 if u256.NewUintFromInt64(balance).Lt(amount) {
74 panic("insufficient balance in router for callback")
75 }
76
77 poolAddr := access.MustGetAddress(prbac.ROLE_POOL.String())
78 routerAddr := access.MustGetAddress(prbac.ROLE_ROUTER.String())
79
80 if payer == routerAddr {
81 common.SafeGRC20Transfer(cross, token, poolAddr, amount.Int64())
82 } else {
83 common.SafeGRC20TransferFrom(cross, token, payer, poolAddr, amount.Int64())
84 }
85}