doc.gno
5.86 Kb · 151 lines
1// Package referral implements a referral system on Gno. It allows
2// authorized contracts to register, update, or remove referral
3// relationships. A referral link is defined as a mapping from one
4// address (the "user") to another address (the "referrer").
5//
6// ## Overview
7//
8// The referral package is composed of the following components:
9//
10// 1. **errors.gno**: Defines error types for invalid addresses,
11// unauthorized callers, self-referrals, rate limits, and missing referrals.
12// 2. **assert.gno**: Checks whether a caller has an authorized role.
13// 3. **type.gno**: Defines the ReferralKeeper interface and the contract-address
14// sentinel used to request removal.
15// 4. **keeper.gno**: Implements ReferralKeeper with BPTree storage. Non-removal
16// registrations and updates have a 24-hour cooldown.
17// 5. **global_keeper.gno**: Exposes the public API and emits referral events.
18//
19// ## Public API
20//
21// The package exposes the following public functions:
22//
23// - GetReferral(addr string) string: Returns the referrer address for
24// the given user. Returns empty string if not found.
25// - HasReferral(addr string) bool: Returns true if the user has a
26// registered referrer.
27// - IsEmpty() bool: Returns true if no referral relationships exist.
28// - GetLastOpTimestamp(addr string) (int64, error): Returns the last
29// non-removal registration or update timestamp for the user.
30// - TryRegister(cur realm, addr address, referral string) string:
31// Empty input reads the stored referral without authorization. A non-empty
32// input registers, updates, or removes a relationship and returns the
33// effective referrer string. Passing ContractAddress() requests removal.
34//
35// ## Workflow
36//
37// Typical usage of this contract follows these steps:
38//
39// 1. A caller uses TryRegister to resolve the effective referrer. Empty input
40// only reads; non-empty input must come from an authorized role.
41// 2. The keeper validates the caller's permissions via assertValidCaller.
42// 3. Address validation ensures the user address is valid, the referral is
43// valid for registration, and self-referrals are rejected. The contract's
44// own address is the removal sentinel.
45// 4. The 24-hour rate limit is checked for non-removal registrations and
46// updates. Removal bypasses this check.
47// 5. Successful non-removal writes store a new timestamp. Successful
48// non-empty writes emit a RegisterReferral event.
49//
50// ## Authorized Callers
51//
52// Only contracts with the following roles can modify referral data:
53//
54// - ROLE_GOVERNANCE: Governance contracts
55// - ROLE_GOV_STAKER: Governance staker contracts
56// - ROLE_ROUTER: Router contracts
57// - ROLE_POSITION: Position manager contracts
58// - ROLE_STAKER: Staker contracts
59// - ROLE_LAUNCHPAD: Launchpad contracts
60//
61// ## Rate Limiting
62//
63// To prevent abuse, the system enforces a 24-hour cooldown between non-removal
64// registrations or updates for each address. This means:
65//
66// - A new referral can only be registered once per 24 hours per address.
67// - Updates are also subject to the same rate limit.
68// - Removal via the contract-address sentinel bypasses the rate-limit check.
69// - Removal does not overwrite the previous timestamp, so immediate
70// re-registration can still be rejected during the prior cooldown.
71// - Attempts that exceed the cooldown return ErrTooManyRequests.
72//
73// ## Events
74//
75// The package emits the following events:
76//
77// - RegisterReferral: Emitted for every successful non-empty write, including
78// creation, update, and removal.
79// - ReferralRegistrationFailed: Emitted when an authorized non-empty write
80// fails.
81// - Empty referral queries do not emit events.
82//
83// ## Error Handling
84//
85// The package defines several error types:
86// - `ErrInvalidAddress`: Returned when an address format is invalid
87// - `ErrSelfReferral`: Returned when attempting to set self as referrer
88// - `ErrUnauthorized`: Returned when the caller lacks permission
89// - `ErrTooManyRequests`: Returned when rate limit is exceeded (24-hour cooldown)
90// - `ErrNotFound`: Returned when attempting to get a non-existent referral
91// - `ErrInvalidTime`: Returned when the stored timestamp format is invalid
92//
93// ## Example: Integration with Router Contract
94//
95// The router contract can register referrals during swap operations:
96//
97// ```go
98//
99// import (
100// "gno.land/r/gnoswap/referral/v1"
101// )
102//
103// func SwapWithReferral(cur realm, referralCode string, ...) {
104// // Get the caller address
105// caller := cur.Previous().Address()
106//
107// actualReferrer := referral.TryRegister(cross(cur), caller, referralCode)
108//
109// // Continue with swap logic...
110// }
111//
112// ```
113//
114// ## Example: Checking Referral for Rewards
115//
116// Other contracts can check referral relationships for reward distribution:
117//
118// ```go
119//
120// import (
121// "gno.land/r/gnoswap/referral/v1"
122// )
123//
124// func DistributeRewards(user address, amount uint64) {
125// // Check if user has a referrer
126// if referral.HasReferral(user.String()) {
127// referrerAddr := referral.GetReferral(user.String())
128// // Calculate and distribute referral bonus
129// referrerBonus := amount * referralRate / 100
130// sendReward(address(referrerAddr), referrerBonus)
131// }
132// }
133//
134// ```
135//
136// ## Limitations and Constraints
137//
138// - A user can have only one referrer at a time.
139// - Self-referral is not allowed.
140// - Non-removal registrations and updates are rate-limited to once per 24
141// hours per address.
142// - Only callers with an authorized role can perform non-empty writes.
143// - The referral contract's own address is the removal sentinel; the zero
144// address is invalid.
145//
146// ## Notes
147//
148// - The contract uses RBAC (Role-Based Access Control) for authorization.
149// - Rate-limit state persists across transactions.
150// - The referral relationship is stored in a BPTree.
151package referral