Kind Realm (renderable)
Name v1
Namespace gnoswap / position
Exported functions 1
Module gno.land/r/gnoswap/position/v1
gno 0.9 render.gno gno
⧉
1 package position 2 3 import ( 4 "chain" 5 "strconv" 6 "strings" 7 8 NewPositionV1 (positionStore interface {GetPosition func(uint64) (gno.land/r/gnoswap/position.Position, bool); GetPositionNextID func() uint64; GetPositions func() *gno.land/p/nt/bptree/v0.BPTree; HasPosition func(uint64) bool; HasPositionNextIDStoreKey func() bool; HasPositionsStoreKey func() bool; RemovePosition func(int, .uverse.realm, uint64) .uverse.error; SetPosition func(int, .uverse.realm, uint64, gno.land/r/gnoswap/position.Position) .uverse.error; SetPositionNextID func(int, .uverse.realm, uint64) .uverse.error; SetPositions func(int, .uverse.realm, *gno.land/p/nt/bptree/v0.BPTree) .uverse.error}, accessor interface {Approve func(int, .uverse.realm, .uverse.address, gno.land/p/nt/grc721/v0.TokenID) .uverse.error; Burn func(int, .uverse.realm, gno.land/p/nt/grc721/v0.TokenID); Exists func(gno.land/p/nt/grc721/v0.TokenID) bool; Mint func(int, .uverse.realm, .uverse.address, gno.land/p/nt/grc721/v0.TokenID) gno.land/p/nt/grc721/v0.TokenID; OwnerOf func(gno.land/p/nt/grc721/v0.TokenID) (.uverse.address, .uverse.error); TotalSupply func() int64}) interface {CollectFee func(int, .uverse.realm, uint64) (uint64, string, string, string, string, string); DecreaseLiquidity func(int, .uverse.realm, uint64, string, string, string, int64) (uint64, string, string, string, string, string, string); GetPositionFeeGrowthInside0LastX128 func(uint64) (string, .uverse.error); GetPositionFeeGrowthInside1LastX128 func(uint64) (string, .uverse.error); GetPositionFeeGrowthInsideLastX128 func(uint64) (string, string, .uverse.error); GetPositionLiquidity func(uint64) (string, .uverse.error); GetPositionOperator func(uint64) (.uverse.address, .uverse.error); GetPositionOwner func(uint64) (.uverse.address, .uverse.error); GetPositionPoolKey func(uint64) (string, .uverse.error); GetPositionTickLower func(uint64) (int32, .uverse.error); GetPositionTickUpper func(uint64) (int32, .uverse.error); GetPositionTicks func(uint64) (int32, int32, .uverse.error); GetPositionTokenBalances func(uint64) (int64, int64, .uverse.error); GetPositionTokensOwed func(uint64) (int64, int64, .uverse.error); GetPositionTokensOwed0 func(uint64) (int64, .uverse.error); GetPositionTokensOwed1 func(uint64) (int64, .uverse.error); GetPositions func() *gno.land/p/nt/bptree/rotree/v0.ReadOnlyTree; GetUnclaimedFee func(uint64) (*gno.land/p/gnoswap/uint256/v1.Uint, *gno.land/p/gnoswap/uint256/v1.Uint, .uverse.error); IncreaseLiquidity func(int, .uverse.realm, uint64, string, string, string, string, int64) (uint64, string, string, string, string); IsBurned func(uint64) (bool, .uverse.error); IsInRange func(uint64) (bool, .uverse.error); Mint func(int, .uverse.realm, string, string, uint32, int32, int32, string, string, string, string, int64, .uverse.address, string) (uint64, string, string, string); Render func(string) string; Reposition func(int, .uverse.realm, uint64, int32, int32, string, string, string, string, int64) (uint64, string, int32, int32, string, string); SetPositionOperator func(int, .uverse.realm, uint64, .uverse.address)}
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
This realm does not provide renderable output (vm/qrender → NoRenderDeclError).
View on gnoweb ↗ vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.
"gno.land/p/moul/md/v0"
9 "gno.land/p/moul/mdtable/v0"
10 ufmt "gno.land/p/nt/ufmt/v0"
11
12 "gno.land/r/gnoswap/halt/v1"
13 positionRoot "gno.land/r/gnoswap/position"
14 )
15
16 func (p *positionV1) Render(path string ) string {
17 if path == "" {
18 return p.renderSummary()
19 }
20
21 positionID, ok := parsePositionRenderPath(path)
22 if !ok {
23 return "404\n"
24 }
25
26 storedPosition, exists := p.store.GetPosition(positionID)
27 if !exists {
28 return "404\n"
29 }
30
31 return p.renderPositionDetail(positionID, storedPosition)
32 }
33
34 func (p *positionV1) renderSummary() string {
35 out := md.H1( "Gnoswap Position" )
36 out += md.Paragraph(
37 "Position records remain stored after burning. The record count includes burned " +
38 "positions and is not a count of active liquidity positions. Use " +
39 md.InlineCode( "id/<id>" ) + " for one stored record, for example " +
40 md.Link( "id/1" , "/r/gnoswap/position:id/1" ) +
41 ". The detail route performs one keyed lookup and does not enumerate positions or recompute claimable values." ,
42 )
43 runtimeTable := mdtable.Table{
44 Headers: [] string { "Field" , "Value" },
45 Rows: [][] string {
46 { "Realm address" , md.InlineCode(chain.PackageAddress( "gno.land/r/gnoswap/position" ).String())},
47 { "Active implementation" , renderPackageLink(positionRoot.GetImplementationPackagePath())},
48 { "Position operations halted" , ufmt.Sprintf( "%t" , halt.IsHaltedPosition())},
49 { "Withdrawals halted" , ufmt.Sprintf( "%t" , halt.IsHaltedWithdraw())},
50 },
51 }
52 out += md.H2( "Runtime" ) + runtimeTable.String()
53
54 records := mdtable.Table{
55 Headers: [] string { "Field" , "Value" },
56 Rows: [][] string {
57 { "Stored position records (including burned)" , ufmt.Sprintf( "%d" , p.store.GetPositions().Size())},
58 { "Next position ID" , ufmt.Sprintf( "%d" , p.store.GetPositionNextID())},
59 },
60 }
61 return out + md.H2( "Stored records" ) + records.String()
62 }
63
64 func (p *positionV1) renderPositionDetail(positionID uint64 , stored positionRoot.Position) string {
65 status := "Active"
66 if stored.Burned() {
67 status = "Burned (record retained)"
68 }
69
70 owner := "unavailable"
71 ownerAddress, err := p.nftAccessor.OwnerOf(positionIdFrom(positionID))
72 if err == nil && ownerAddress != "" {
73 owner = ownerAddress.String()
74 }
75
76 token0, token1, poolFee, validPoolKey := splitPoolKeyForRender(stored.PoolKey())
77 token0Reference := "unavailable (stored pool key is not token0:token1:fee)"
78 token1Reference := token0Reference
79 if validPoolKey {
80 token0Reference = renderPackageLink(token0)
81 token1Reference = renderPackageLink(token1)
82 }
83
84 out := md.H1(ufmt.Sprintf( "Gnoswap Position %d" , positionID))
85 out += md.Paragraph(
86 "This page reads one persisted position record. Stored accounting fields are " +
87 "shown as stored; claimable fees and current token balances are recomputed " +
88 "values and are intentionally not queried here." ,
89 )
90 identity := mdtable.Table{
91 Headers: [] string { "Field" , "Value" },
92 Rows: [][] string {
93 { "Position ID" , ufmt.Sprintf( "%d" , positionID)},
94 { "Status" , status},
95 { "Owner" , owner},
96 },
97 }
98 out += md.H2( "Identity" ) + identity.String()
99
100 poolAndRange := mdtable.Table{
101 Headers: [] string { "Field" , "Value" },
102 Rows: [][] string {
103 { "Pool key" , md.InlineCode(stored.PoolKey())},
104 { "Token 0 reference" , token0Reference},
105 { "Token 1 reference" , token1Reference},
106 { "Pool fee (from stored key)" , poolFee},
107 { "Lower tick (stored)" , ufmt.Sprintf( "%d" , stored.TickLower())},
108 { "Upper tick (stored)" , ufmt.Sprintf( "%d" , stored.TickUpper())},
109 },
110 }
111 out += md.H2( "Pool and range" ) + poolAndRange.String()
112
113 accounting := mdtable.Table{
114 Headers: [] string { "Field" , "Value" },
115 Rows: [][] string {
116 { "Liquidity (stored)" , stored.Liquidity()},
117 { "Fee growth token 0 inside, last X128 (stored)" , stored.FeeGrowthInside0LastX128()},
118 { "Fee growth token 1 inside, last X128 (stored)" , stored.FeeGrowthInside1LastX128()},
119 { "Token 0 owed (stored accounting)" , ufmt.Sprintf( "%d" , stored.TokensOwed0())},
120 { "Token 1 owed (stored accounting)" , ufmt.Sprintf( "%d" , stored.TokensOwed1())},
121 { "Claimable fees / current token balances" , "Not rendered; would require recomputation" },
122 },
123 }
124 return out + md.H2( "Stored accounting" ) + accounting.String()
125 }
126
127 func parsePositionRenderPath(path string ) ( uint64 , bool ) {
128 const prefix = "id/"
129 if len(path) <= len(prefix) || path[:len(prefix)] != prefix {
130 return 0 , false
131 }
132
133 id := path[len(prefix):]
134 for i := 0 ; i < len(id); i++ {
135 if id[i] < '0' || id[i] > '9' {
136 return 0 , false
137 }
138 }
139
140 positionID, err := strconv.ParseUint(id, 10 , 64 )
141 if err != nil {
142 return 0 , false
143 }
144
145 return positionID, true
146 }
147
148 func splitPoolKeyForRender(poolKey string ) ( string , string , string , bool ) {
149 parts := strings.Split(poolKey, ":" )
150 if len(parts) != 3 || parts[ 0 ] == "" || parts[ 1 ] == "" || parts[ 2 ] == "" {
151 return "" , "" , "" , false
152 }
153
154 return parts[ 0 ], parts[ 1 ], parts[ 2 ], true
155 }
156
157 func renderPackageLink(path string ) string {
158 if strings.HasPrefix(path, "gno.land/" ) {
159 destination := strings.TrimPrefix(path, "gno.land" )
160 // Token references append .SYMBOL; link to the defining realm.
161 if separator := strings.Index(destination, "." ); separator >= 0 {
162 destination = destination[:separator]
163 }
164 return md.Link(path, destination)
165 }
166
167 return md.InlineCode(path)
168 }
169