Kind Realm (renderable)
Name v0
Namespace moul / x / amm
Exported functions 15
Module gno.land/r/moul/x/amm/v0
gno 0.9 lp_test.gno gno
⧉
1 package amm 2 3 import ( 4 "testing" 5 6 "gno.land/p/nt/grc20/v0" 7 "gno.land/p/nt/testutils/v0" 8 AddLiquidity (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, keyA string, keyB string, maxA int64, maxB int64) int64
AllowanceLP (keyA string, keyB string, owner string, spender string) int64
AmountOut (amountIn int64, reserveIn int64, reserveOut int64) int64
ApproveLP (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, keyA string, keyB string, spender string, amount int64)
LPToken (keyA string, keyB string) string
PoolCount () int
Quote (keyIn string, keyOut string, amountIn int64) int64
RemoveLiquidity (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, keyA string, keyB string, shares int64) (int64, int64)
Render (path string) string
Reserves (keyA string, keyB string) (int64, int64)
SharesOf (keyA string, keyB string, owner string) int64
Swap (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, keyIn string, keyOut string, amountIn int64, minOut int64) int64
TotalShares (keyA string, keyB string) int64
TransferFromLP (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, keyA string, keyB string, from string, to string, amount int64)
TransferLP (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, keyA string, keyB string, to string, amount int64)
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
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/nt/uassert/v0"
9 "gno.land/r/nt/grc20reg/v0"
10 )
11
12 // A third token, so a second pool can prove each one mints its own LP token.
13 var (
14 tokCCC *grc20.Token
15 ledCCC *grc20.PrivateLedger
16 keyCCC string
17 )
18
19 func init(cur realm) {
20 tokCCC, ledCCC = grc20.NewToken( "Test Gamma" , "CCC" , 6 , 2 , cur)
21 keyCCC = grc20reg.Register(cross(cur), tokCCC, "" )
22 }
23
24 // TestLPPositionIsARealToken is the whole point of v1: the position exists
25 // outside this realm, as an ordinary registered GRC20.
26 func TestLPPositionIsARealToken(cur realm, t *testing.T) {
27 reset()
28 alice := testutils.TestAddress( "lp-alice" )
29 fund(alice, 10_000_000 )
30 testing.SetRealm(testing.NewUserRealm(alice))
31 minted := AddLiquidity(cross(cur), keyAAA, keyBBB, 1_000_000 , 4_000_000 )
32
33 // Readable by any realm that knows the key, without importing this one.
34 lp := grc20reg.MustGet(LPToken(keyAAA, keyBBB))
35 uassert.Equal(t, minted, lp.BalanceOf(alice))
36 uassert.Equal(t, minted, lp.TotalSupply())
37 uassert.Equal(t, minted, TotalShares(keyAAA, keyBBB))
38 // The LP unit is token A at seed time, so it mirrors token A's decimals.
39 uassert.Equal(t, tokAAA.GetDecimals(), lp.GetDecimals())
40 uassert.Equal(t, "AMM LP AAA/BBB" , lp.GetName())
41 }
42
43 // TestLPIsTransferable: a position can change hands without touching the pool.
44 func TestLPIsTransferable(cur realm, t *testing.T) {
45 reset()
46 alice := testutils.TestAddress( "xfer-alice" )
47 bob := testutils.TestAddress( "xfer-bob" )
48 fund(alice, 10_000_000 )
49
50 testing.SetRealm(testing.NewUserRealm(alice))
51 AddLiquidity(cross(cur), keyAAA, keyBBB, 1_000_000 , 4_000_000 )
52 TransferLP(cross(cur), keyAAA, keyBBB, bob, 500_000 )
53
54 uassert.Equal(t, int64 ( 500_000 ), SharesOf(keyAAA, keyBBB, alice))
55 uassert.Equal(t, int64 ( 500_000 ), SharesOf(keyAAA, keyBBB, bob))
56
57 // Bob exits on a position he was given, having never deposited anything.
58 // In v0 this is not expressible at all.
59 testing.SetRealm(testing.NewUserRealm(bob))
60 gotA, gotB := RemoveLiquidity(cross(cur), keyAAA, keyBBB, 500_000 )
61 uassert.Equal(t, int64 ( 500_000 ), gotA)
62 uassert.Equal(t, int64 ( 2_000_000 ), gotB)
63 uassert.Equal(t, int64 ( 500_000 ), tokAAA.BalanceOf(bob), "bob was never funded" )
64 }
65
66 // TestLPAllowance: the approve/transferFrom surface v1 gains, and the abort
67 // when it is spent past its limit.
68 func TestLPAllowance(cur realm, t *testing.T) {
69 reset()
70 alice := testutils.TestAddress( "allow-alice" )
71 carol := testutils.TestAddress( "allow-carol" )
72 fund(alice, 10_000_000 )
73
74 testing.SetRealm(testing.NewUserRealm(alice))
75 AddLiquidity(cross(cur), keyAAA, keyBBB, 1_000_000 , 1_000_000 )
76 ApproveLP(cross(cur), keyAAA, keyBBB, carol, 300_000 )
77 uassert.Equal(t, int64 ( 300_000 ), AllowanceLP(keyAAA, keyBBB, alice, carol))
78
79 testing.SetRealm(testing.NewUserRealm(carol))
80 TransferFromLP(cross(cur), keyAAA, keyBBB, alice, carol, 300_000 )
81 uassert.Equal(t, int64 ( 300_000 ), SharesOf(keyAAA, keyBBB, carol))
82 uassert.Equal(t, int64 ( 700_000 ), SharesOf(keyAAA, keyBBB, alice))
83 uassert.Equal(t, int64 ( 0 ), AllowanceLP(keyAAA, keyBBB, alice, carol))
84
85 uassert.AbortsContains(t, cur, "insufficient allowance" , func () {
86 TransferFromLP(cross(cur), keyAAA, keyBBB, alice, carol, 1 )
87 })
88 }
89
90 // TestEachPoolMintsItsOwnLPToken: two pools, two distinct registered tokens.
91 func TestEachPoolMintsItsOwnLPToken(cur realm, t *testing.T) {
92 reset()
93 alice := testutils.TestAddress( "two-alice" )
94 fund(alice, 10_000_000 )
95 ledCCC.Mint(alice, 10_000_000 )
96 ledCCC.Approve(alice, self(), 10_000_000 )
97
98 testing.SetRealm(testing.NewUserRealm(alice))
99 AddLiquidity(cross(cur), keyAAA, keyBBB, 1_000_000 , 4_000_000 )
100 AddLiquidity(cross(cur), keyAAA, keyCCC, 2_000_000 , 2_000_000 )
101
102 ab := LPToken(keyAAA, keyBBB)
103 ac := LPToken(keyAAA, keyCCC)
104 uassert.NotEqual(t, ab, ac, "one LP token per pool" )
105 uassert.Equal(t, int64 ( 1_000_000 ), grc20reg.MustGet(ab).TotalSupply())
106 uassert.Equal(t, int64 ( 2_000_000 ), grc20reg.MustGet(ac).TotalSupply())
107 uassert.Equal(t, "AMM LP AAA/CCC" , grc20reg.MustGet(ac).GetName())
108
109 // Moving one pool's LP leaves the other alone.
110 TransferLP(cross(cur), keyAAA, keyBBB, testutils.TestAddress( "two-bob" ), 400_000 )
111 uassert.Equal(t, int64 ( 600_000 ), SharesOf(keyAAA, keyBBB, alice))
112 uassert.Equal(t, int64 ( 2_000_000 ), SharesOf(keyAAA, keyCCC, alice))
113 }
114