Search Apps Documentation Source Content File Folder Download Copy Actions Download

recurring.gno

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