Search Apps Documentation Source Content File Folder Download Copy Actions Download State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

swap_callback.gno

2.84 Kb · 95 lines
 1package router
 2
 3import (
 4	"errors"
 5
 6	prbac "gno.land/p/gnoswap/rbac/v1"
 7	u256 "gno.land/p/gnoswap/uint256/v1"
 8	ufmt "gno.land/p/nt/ufmt/v0"
 9
10	"gno.land/r/gnoswap/access/v1"
11	"gno.land/r/gnoswap/common"
12	"gno.land/r/gnoswap/halt/v1"
13)
14
15// SwapCallback implements the pool's SwapCallback interface.
16// The pool invokes it after sending output tokens; the router then transfers the
17// positive input delta to the pool.
18//
19// Parameters:
20//   - _: leading callback discriminator; callers pass 0
21//   - rlm: propagated current realm context; must remain the current crossing frame
22//   - token0Path: token-0 contract path in canonical pool order
23//   - token1Path: token-1 contract path in canonical pool order
24//   - amount0Delta: signed token-0 delta; positive means the pool is owed this amount
25//   - amount1Delta: signed token-1 delta; positive means the pool is owed this amount
26//   - payer: address whose balance supplies the positive input delta
27//
28// Returns:
29//   - err: nil after the owed input transfer; an error for spoofed realm, invalid liquidity delta, or failed payment
30//
31// Positive deltas are tokens the pool must receive; negative deltas are tokens
32// the pool has sent to the recipient.
33func (r *routerV1) SwapCallback(
34	_ int,
35	rlm realm,
36	token0Path, token1Path string,
37	amount0Delta, amount1Delta int64,
38	payer address,
39) error {
40	if !rlm.IsCurrent() {
41		return errors.New(errSpoofedRealm)
42	}
43
44	if amount0Delta <= 0 && amount1Delta <= 0 {
45		return makeErrorWithDetails(
46			errInsufficientLiquidity,
47			"swap entirely within 0-liquidity region",
48		)
49	}
50
51	halt.AssertIsNotHaltedRouter()
52
53	caller := rlm.Previous().Address()
54	assertIsRouterImplementation(caller)
55
56	var tokenToPay string
57	var amountToPay int64
58
59	// amount0Delta > 0 means pool wants token0
60	// amount1Delta > 0 means pool wants token1
61	if amount0Delta > 0 {
62		amountToPay = amount0Delta
63		tokenToPay = token0Path
64	} else {
65		amountToPay = amount1Delta
66		tokenToPay = token1Path
67	}
68
69	// Transfer tokens from router to pool
70	// The router should already have the tokens from the user
71	r.transferToPool(0, rlm, tokenToPay, u256.NewUintFromInt64(amountToPay), payer)
72
73	return nil
74}
75
76// transferToPool transfers tokens from router to pool
77func (r *routerV1) transferToPool(_ int, rlm realm, token string, amount *u256.Uint, payer address) {
78	balance := common.BalanceOf(token, payer)
79
80	if u256.NewUintFromInt64(balance).Lt(amount) {
81		panic(makeErrorWithDetails(
82			errInsufficientBalance,
83			ufmt.Sprintf("token=%s, required=%d, available=%d, payer=%s", token, amount.Int64(), balance, payer.String()),
84		))
85	}
86
87	poolAddr := access.MustGetAddress(prbac.ROLE_POOL.String())
88	routerAddr := access.MustGetAddress(prbac.ROLE_ROUTER.String())
89
90	if payer == routerAddr {
91		common.SafeGRC20Transfer(0, rlm, token, poolAddr, amount.Int64())
92	} else {
93		common.SafeGRC20TransferFrom(0, rlm, token, payer, poolAddr, amount.Int64())
94	}
95}