recurring.gno
2.82 Kb ยท 104 lines
1package recurring
2
3import (
4 "std"
5 "time"
6
7 "gno.land/p/demo/avl"
8 "gno.land/p/demo/ownable"
9)
10
11// RecurringSubscription represents a subscription that requires periodic payments.
12// It includes the duration of the subscription and the amount required per period.
13type RecurringSubscription struct {
14 ownable.Ownable
15 duration time.Duration
16 amount int64
17 subs *avl.Tree // std.Address -> time.Time
18}
19
20// NewRecurringSubscription creates and returns a new recurring subscription.
21func NewRecurringSubscription(duration time.Duration, amount int64) *RecurringSubscription {
22 return &RecurringSubscription{
23 Ownable: *ownable.New(),
24 duration: duration,
25 amount: amount,
26 subs: avl.NewTree(),
27 }
28}
29
30// HasValidSubscription verifies if the caller has an active recurring subscription.
31func (rs *RecurringSubscription) HasValidSubscription(addr std.Address) error {
32 expTime, exists := rs.subs.Get(addr.String())
33 if !exists {
34 return ErrNoSub
35 }
36
37 if time.Now().After(expTime.(time.Time)) {
38 return ErrSubExpired
39 }
40
41 return nil
42}
43
44// processSubscription processes the payment for a given receiver and renews or adds their subscription.
45func (rs *RecurringSubscription) processSubscription(receiver std.Address) error {
46 amount := std.OriginSend()
47
48 if amount.AmountOf("ugnot") != rs.amount {
49 return ErrAmt
50 }
51
52 expTime, exists := rs.subs.Get(receiver.String())
53
54 // If the user is already a subscriber but his subscription has expired, authorize renewal
55 if exists {
56 expiration := expTime.(time.Time)
57 if time.Now().Before(expiration) {
58 return ErrAlreadySub
59 }
60 }
61
62 // Renew or add subscription
63 newExpiration := time.Now().Add(rs.duration)
64 rs.subs.Set(receiver.String(), newExpiration)
65
66 return nil
67}
68
69// Subscribe handles the payment for the caller's subscription.
70func (rs *RecurringSubscription) Subscribe() error {
71 caller := std.CurrentRealm().Address()
72
73 return rs.processSubscription(caller)
74}
75
76// GiftSubscription allows the user to pay for a subscription for another user (receiver).
77func (rs *RecurringSubscription) GiftSubscription(receiver std.Address) error {
78 return rs.processSubscription(receiver)
79}
80
81// GetExpiration returns the expiration date of the recurring subscription for a given caller.
82func (rs *RecurringSubscription) GetExpiration(addr std.Address) (time.Time, error) {
83 expTime, exists := rs.subs.Get(addr.String())
84 if !exists {
85 return time.Time{}, ErrNoSub
86 }
87
88 return expTime.(time.Time), nil
89}
90
91// UpdateAmount allows the owner of the subscription contract to change the required subscription amount.
92func (rs *RecurringSubscription) UpdateAmount(newAmount int64) error {
93 if !rs.OwnedByCurrent() {
94 return ErrNotAuthorized
95 }
96
97 rs.amount = newAmount
98 return nil
99}
100
101// GetAmount returns the current amount required for each subscription period.
102func (rs *RecurringSubscription) GetAmount() int64 {
103 return rs.amount
104}