Search Apps Documentation Source Content File Folder Download Copy Actions Download

offer.gno

2.45 Kb · 79 lines
 1package gnogle_market2
 2
 3import (
 4	"chain"
 5	"chain/runtime"
 6	"strconv"
 7
 8	"gno.land/p/nt/avl/v0"
 9	nft "gno.land/r/g18wk4a80cr7dqa25vfka2yug5n3pd50udled6y3/gnogle_nft2"
10)
11
12// Offer is a standing bid on a token (listed or not). The offered GNOT is
13// escrowed in the market until accepted or withdrawn.
14type Offer struct {
15	collID  string
16	tokenID string
17	buyer   address
18	amount  int64
19	madeAt  int64
20}
21
22var offers avl.Tree // "collID/tokenID/buyer" -> *Offer
23
24func offerKey(collID, tokenID string, buyer address) string {
25	return collID + "/" + tokenID + "/" + buyer.String()
26}
27
28// MakeOffer escrows GNOT as an offer on a token. Re-offering replaces (refunds)
29// the caller's previous offer.
30func MakeOffer(cur realm, collID, tokenID string) {
31	assertUserCall(cur)
32	buyer := cur.Previous().Address()
33	amount := receivedUgnot()
34	if amount <= 0 {
35		panic("an offer must include a positive ugnot amount")
36	}
37	if nft.OwnerOf(collID, tokenID) == buyer {
38		panic("you already own this token")
39	}
40	k := offerKey(collID, tokenID, buyer)
41	if v, ok := offers.Get(k); ok {
42		payout(cur, buyer, v.(*Offer).amount)
43	}
44	offers.Set(k, &Offer{collID, tokenID, buyer, amount, runtime.ChainHeight()})
45	chain.Emit("OfferMade", "collection", collID, "tokenId", tokenID, "buyer", buyer.String(), "amount", strconv.FormatInt(amount, 10))
46}
47
48// CancelOffer withdraws the caller's offer and refunds the escrow.
49func CancelOffer(cur realm, collID, tokenID string) {
50	assertUserCall(cur)
51	buyer := cur.Previous().Address()
52	k := offerKey(collID, tokenID, buyer)
53	v, ok := offers.Get(k)
54	if !ok {
55		panic("you have no offer on this token")
56	}
57	o := v.(*Offer)
58	offers.Remove(k)
59	payout(cur, buyer, o.amount)
60	chain.Emit("OfferCancelled", "collection", collID, "tokenId", tokenID, "buyer", buyer.String())
61}
62
63// AcceptOffer lets the current owner accept a buyer's offer. The owner must hold
64// the token and have approved this market.
65func AcceptOffer(cur realm, collID, tokenID string, buyer address) {
66	assertUserCall(cur)
67	owner := cur.Previous().Address()
68	requireOwnerAndApproval(cur, collID, tokenID, owner)
69	k := offerKey(collID, tokenID, buyer)
70	v, ok := offers.Get(k)
71	if !ok {
72		panic("no such offer")
73	}
74	o := v.(*Offer)
75	offers.Remove(k)
76	nft.TransferFrom(cross(cur), collID, owner, buyer, tokenID)
77	settle(cur, collID, tokenID, owner, buyer, o.amount, "offer")
78	chain.Emit("OfferAccepted", "collection", collID, "tokenId", tokenID, "buyer", buyer.String(), "seller", owner.String(), "amount", strconv.FormatInt(o.amount, 10))
79}