Search Apps Documentation Source Content File Folder Download Copy Actions Download 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