Search Apps Documentation Source Content File Folder Download Copy Actions Download

doc.gno

5.65 Kb ยท 153 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 various failure scenarios
 11//     such as invalid address, unauthorized caller, self-referral,
 12//     rate limit exceeded, and referral not found.
 13//  2. **utils.gno**: Contains the isValidCaller function that checks
 14//     if the caller has an authorized role (governance, router, position,
 15//     staker, or launchpad contracts).
 16//  3. **type.gno**: Defines the ReferralKeeper interface and event type
 17//     constants for register, update, and remove operations.
 18//  4. **keeper.gno**: Implements the ReferralKeeper interface using an
 19//     AVL tree for storage. Includes rate limiting (24-hour cooldown)
 20//     to prevent abuse of referral operations.
 21//  5. **global_keeper.gno**: Exposes the public API functions that
 22//     external contracts can use to interact with the referral system.
 23//
 24// ## Public API
 25//
 26// The package exposes the following public functions:
 27//
 28//   - GetReferral(addr string) string: Returns the referrer address for
 29//     the given user address. Returns empty string if not found.
 30//   - HasReferral(addr string) bool: Returns true if the user has a
 31//     registered referrer.
 32//   - IsEmpty() bool: Returns true if no referral relationships exist.
 33//   - GetLastOpTimestamp(addr string) (int64, error): Returns the last
 34//     referral operation timestamp for the given user address.
 35//   - TryRegister(cur realm, addr address, referral string) bool:
 36//     Attempts to register a new referral. Returns true on success.
 37//
 38// ## Workflow
 39//
 40// Typical usage of this contract follows these steps:
 41//
 42//  1. An authorized contract (router, staker, etc.) calls TryRegister
 43//     to create a referral relationship.
 44//  2. The keeper validates the caller's permissions via isValidCaller.
 45//  3. Address validation ensures both addresses are valid and not
 46//     self-referencing.
 47//  4. Rate limiting checks prevent operations more than once per 24 hours.
 48//  5. The referral is stored in the AVL tree and an event is emitted.
 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 period between
 64// operations for each address. This means:
 65//
 66//   - A new referral can only be registered once per 24 hours per address
 67//   - Updates and removals are also subject to the same rate limit
 68//   - Attempting operations within the cooldown period returns ErrTooManyRequests
 69//
 70// ## Events
 71//
 72// The package emits the following events:
 73//
 74//   - RegisterReferral: Emitted when a new referral is created
 75//   - ReferralRegistrationFailed: Emitted when TryRegister fails
 76//
 77// ## Error Handling
 78//
 79// The package defines several error types:
 80//   - `ErrInvalidAddress`: Returned when an address format is invalid
 81//   - `ErrSelfReferral`: Returned when attempting to set self as referrer
 82//   - `ErrUnauthorized`: Returned when the caller lacks permission
 83//   - `ErrTooManyRequests`: Returned when rate limit is exceeded (24-hour cooldown)
 84//   - `ErrNotFound`: Returned when attempting to get a non-existent referral
 85//   - `ErrInvalidTime`: Returned when the stored timestamp format is invalid
 86//
 87// ## Example: Integration with Router Contract
 88//
 89// The router contract can register referrals during swap operations:
 90//
 91// ```go
 92//
 93//	import (
 94//	    "chain/runtime"
 95//
 96//	    "gno.land/r/gnoswap/referral"
 97//	)
 98//
 99//	func SwapWithReferral(cur realm, referralCode string, ...) {
100//	    // Get the caller address
101//	    caller := runtime.PreviousRealm().Address()
102//
103//	    // Register the referral if provided
104//	    if referralCode != "" {
105//	        success := referral.TryRegister(cross, caller, referralCode)
106//	        actualReferrer := referralCode
107//	        if !success {
108//	            // Get existing referral if registration failed
109//	            actualReferrer = referral.GetReferral(caller.String())
110//	        }
111//	    }
112//
113//	    // Continue with swap logic...
114//	}
115//
116// ```
117//
118// ## Example: Checking Referral for Rewards
119//
120// Other contracts can check referral relationships for reward distribution:
121//
122// ```go
123//
124//	import (
125//	    "gno.land/r/gnoswap/referral"
126//	)
127//
128//	func DistributeRewards(user address, amount uint64) {
129//	    // Check if user has a referrer
130//	    if referral.HasReferral(user.String()) {
131//	        referrerAddr := referral.GetReferral(user.String())
132//	        // Calculate and distribute referral bonus
133//	        referrerBonus := amount * referralRate / 100
134//	        sendReward(address(referrerAddr), referrerBonus)
135//	    }
136//	}
137//
138// ```
139//
140// ## Limitations and Constraints
141//
142//   - A user can have only one referrer at a time
143//   - Self-referral is not allowed
144//   - Operations are rate-limited to once per 24 hours per address
145//   - Only authorized contracts can register/update/remove referrals
146//   - Zero address as referrer triggers removal of the referral
147//
148// ## Notes
149//
150//   - The contract uses RBAC (Role-Based Access Control) for authorization
151//   - Rate limiting state persists across transactions
152//   - Events are emitted for all state changes for off-chain tracking
153package referral