lp_test.gno
4.20 Kb · 113 lines
1package amm
2
3import (
4 "testing"
5
6 "gno.land/p/nt/grc20/v0"
7 "gno.land/p/nt/testutils/v0"
8 "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.
13var (
14 tokCCC *grc20.Token
15 ledCCC *grc20.PrivateLedger
16 keyCCC string
17)
18
19func 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.
26func 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.
44func 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.
68func 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.
91func 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}