Skip to content Search Apps Documentation Source Content File Folder Download Copy Actions State String Boolean Number Struct Map Slice Pointer Function Closure Reference Nil Package Type Interface Unknown

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