factory_param.gno
3.16 Kb · 126 lines
1package v1
2
3import (
4 "strings"
5
6 u256 "gno.land/p/gnoswap/uint256"
7 ufmt "gno.land/p/nt/ufmt/v0"
8 "gno.land/r/gnoswap/pool"
9)
10
11var Q192 = u256.Zero().Lsh(u256.One(), 192)
12
13var (
14 minSqrtRatio = u256.MustFromDecimal(MIN_SQRT_RATIO)
15 maxSqrtRatio = u256.MustFromDecimal(MAX_SQRT_RATIO)
16)
17
18const (
19 FeeTier100 uint32 = 100
20 FeeTier500 uint32 = 500
21 FeeTier3000 uint32 = 3000
22 FeeTier10000 uint32 = 10000
23)
24
25const (
26 MIN_SQRT_RATIO string = "4295128739"
27 MAX_SQRT_RATIO string = "1461446703485210103287273052203988822378723970342"
28)
29
30// poolCreateConfig holds the essential parameters for creating a new pool.
31type poolCreateConfig struct {
32 token0Path string
33 token1Path string
34 fee uint32
35 sqrtPriceX96 *u256.Uint
36 tickSpacing int32
37 slot0FeeProtocol uint8
38}
39
40// newPoolParams defines the essential parameters for creating a new pool.
41func newPoolParams(
42 token0Path string,
43 token1Path string,
44 fee uint32,
45 sqrtPriceX96 string,
46 tickSpacing int32,
47 slot0FeeProtocol uint8,
48) *poolCreateConfig {
49 price := u256.MustFromDecimal(sqrtPriceX96)
50 return &poolCreateConfig{
51 token0Path: token0Path,
52 token1Path: token1Path,
53 fee: fee,
54 sqrtPriceX96: price,
55 tickSpacing: tickSpacing,
56 slot0FeeProtocol: slot0FeeProtocol,
57 }
58}
59
60func (p *poolCreateConfig) SqrtPriceX96() *u256.Uint { return p.sqrtPriceX96 }
61func (p *poolCreateConfig) TickSpacing() int32 { return p.tickSpacing }
62func (p *poolCreateConfig) Token0Path() string { return p.token0Path }
63func (p *poolCreateConfig) Token1Path() string { return p.token1Path }
64func (p *poolCreateConfig) Fee() uint32 { return p.fee }
65
66func (p *poolCreateConfig) update() error {
67 token0Path := p.token0Path
68 token1Path := p.token1Path
69
70 // Always validate that the price is within valid range
71 if err := validateSqrtPriceX96(p.sqrtPriceX96); err != nil {
72 return err
73 }
74
75 if !p.isInOrder() {
76 token0Path, token1Path = token1Path, token0Path
77
78 // newPrice = 2^192 / oldPrice
79 newPrice := u256.Zero().Div(Q192, p.sqrtPriceX96)
80
81 // Check if calculated price is within valid range
82 if err := validateSqrtPriceX96(newPrice); err != nil {
83 return err
84 }
85
86 p.sqrtPriceX96 = newPrice
87 }
88
89 p.token0Path = token0Path
90 p.token1Path = token1Path
91
92 return nil
93}
94
95// isInOrder checks if token paths are in lexicographical (or, alphabetical) order
96func (p *poolCreateConfig) isInOrder() bool {
97 if strings.Compare(p.token0Path, p.token1Path) < 0 {
98 return true
99 }
100 return false
101}
102
103func (p *poolCreateConfig) poolPath() string {
104 return pool.GetPoolPath(p.token0Path, p.token1Path, p.fee)
105}
106
107// validateSqrtPriceX96 validates that the given sqrtPriceX96 is within valid range
108func validateSqrtPriceX96(sqrtPriceX96 *u256.Uint) error {
109 // Valid range is [minSqrtRatio, maxSqrtRatio) - same as TickMathGetTickAtSqrtRatio
110 if sqrtPriceX96.Lt(minSqrtRatio) || sqrtPriceX96.Gte(maxSqrtRatio) {
111 return makeErrorWithDetails(
112 errOutOfRange,
113 ufmt.Sprintf("sqrtPriceX96(%s) is out of range", sqrtPriceX96.ToString()),
114 )
115 }
116 return nil
117}
118
119func isValidFeeTier(feeTier uint32) bool {
120 switch feeTier {
121 case FeeTier100, FeeTier500, FeeTier3000, FeeTier10000:
122 return true
123 }
124
125 return false
126}