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

Community realm. Read the code first. Community realm, deployed by its author. Read the code before you interact or send coins.

lock.gno

4.18 Kb · 167 lines
  1package kourtv3
  2import (
  3	"strconv"
  4	bptree "gno.land/p/nt/bptree/v0"
  5)
  6func lockedOf(c *Court, who address) int64 {
  7	if c.locked == nil {
  8		return 0
  9	}
 10	if v := c.locked.Get(string(who)); v != nil {
 11		return v.(int64)
 12	}
 13	return 0
 14}
 15func spendable(c *Court, who address) int64 {
 16	s := c.coin.BalanceOf(who) - lockedOf(c, who)
 17	if s < 0 {
 18		return 0
 19	}
 20	return s
 21}
 22func disposable(c *Court, who address) int64 {
 23	claim := lockedOf(c, who)
 24	if v := voteLockedOf(c, who); v > claim {
 25		claim = v
 26	}
 27	d := c.coin.BalanceOf(who) - claim
 28	if d < 0 {
 29		return 0
 30	}
 31	return d
 32}
 33func DisposableOf(courtSlug string, who address) int64 {
 34	return disposable(mustCourt(courtSlug), who)
 35}
 36func ccAmt(n int64) string {
 37	if n < 0 {
 38		return "-" + ccAmt(-n)
 39	}
 40	whole := strconv.FormatInt(n/1_000_000, 10)
 41	frac := n % 1_000_000
 42	if frac == 0 {
 43		return whole
 44	}
 45	f := strconv.FormatInt(frac, 10)
 46	for len(f) < 6 {
 47		f = "0" + f
 48	}
 49	for len(f) > 1 && f[len(f)-1] == '0' {
 50		f = f[:len(f)-1]
 51	}
 52	return whole + "." + f
 53}
 54func mustSpendable(c *Court, who address, amount int64) {
 55	if disposable(c, who) >= amount {
 56		return
 57	}
 58	vl, sl := voteLockedOf(c, who), lockedOf(c, who)
 59	short := "need " + ccAmt(amount) + " CC, you have " + ccAmt(disposable(c, who))
 60	switch {
 61	case vl <= 0 && sl <= 0:
 62		panic("kourtv3: not enough CC — " + short)
 63	case vl > sl:
 64		panic("kourtv3: not enough uncommitted CC — " + short +
 65			" free; " + ccAmt(vl) + " is committed by voting")
 66	case sl > vl:
 67		panic("kourtv3: not enough unstaked CC — " + short +
 68			" free; " + ccAmt(sl) + " is staked")
 69	default:
 70		panic("kourtv3: not enough free CC — " + short +
 71			" free; " + ccAmt(sl) + " is both staked and committed by voting")
 72	}
 73}
 74func mustStakable(c *Court, who address, amount int64) {
 75	if s := spendable(c, who); s < amount {
 76		tail := ""
 77		if l := lockedOf(c, who); l > 0 {
 78			tail = "; " + ccAmt(l) + " is staked"
 79		}
 80		panic("kourtv3: not enough unstaked CC — need " + ccAmt(amount) +
 81			" CC, you have " + ccAmt(s) + tail)
 82	}
 83}
 84func lockStake(c *Court, who address, amount int64) {
 85	if amount <= 0 {
 86		return
 87	}
 88	if c.locked == nil {
 89		c.locked = bptree.NewBPTree32()
 90	}
 91	c.locked.Set(string(who), mustAdd(lockedOf(c, who), amount))
 92}
 93func releaseStake(c *Court, who address, amount int64) {
 94	if amount <= 0 {
 95		return
 96	}
 97	l := lockedOf(c, who)
 98	if amount > l {
 99		panic("kourtv3: releasing more stake than is locked")
100	}
101	if amount == l {
102		c.locked.Remove(string(who))
103		return
104	}
105	c.locked.Set(string(who), l-amount)
106}
107func LockedOf(courtSlug string, who address) int64 {
108	return lockedOf(mustCourt(courtSlug), who)
109}
110func SpendableOf(courtSlug string, who address) int64 {
111	return spendable(mustCourt(courtSlug), who)
112}
113func TransferCC(cur realm, courtSlug string, to address, amount int64) {
114	if !cur.IsCurrent() {
115		panic(errStaleRealm)
116	}
117	if amount <= 0 {
118		panic("kourtv3: transfer amount must be positive")
119	}
120	from := cur.Previous().Address()
121	if from == to {
122		panic("kourtv3: cannot transfer to yourself")
123	}
124	c := mustCourt(courtSlug)
125	if to == c.escrow || from == c.escrow {
126		panic("kourtv3: the court escrow is not a transfer endpoint")
127	}
128	touch(c)
129	mustSpendable(c, from, amount)
130	c.coin.Transfer(from, to, amount)
131}
132func ApproveCC(cur realm, courtSlug string, spender address, amount int64) {
133	if !cur.IsCurrent() {
134		panic(errStaleRealm)
135	}
136	if amount < 0 {
137		panic("kourtv3: negative allowance")
138	}
139	c := mustCourt(courtSlug)
140	owner := cur.Previous().Address()
141	if spender == c.escrow || owner == c.escrow {
142		panic("kourtv3: the court escrow is not a transfer endpoint")
143	}
144	touch(c)
145	c.coin.Approve(owner, spender, amount)
146}
147func TransferFromCC(cur realm, courtSlug string, from, to address, amount int64) {
148	if !cur.IsCurrent() {
149		panic(errStaleRealm)
150	}
151	if amount <= 0 {
152		panic("kourtv3: transfer amount must be positive")
153	}
154	if from == to {
155		panic("kourtv3: cannot transfer to yourself")
156	}
157	c := mustCourt(courtSlug)
158	if to == c.escrow || from == c.escrow {
159		panic("kourtv3: the court escrow is not a transfer endpoint")
160	}
161	touch(c)
162	mustSpendable(c, from, amount)
163	c.coin.TransferFrom(cur.Previous().Address(), from, to, amount)
164}
165func AllowanceCC(courtSlug string, owner, spender address) int64 {
166	return mustCourt(courtSlug).coin.Allowance(owner, spender)
167}