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}