Kind Realm (renderable)
Name v1
Namespace gnoswap / referral
Exported functions 8
Module gno.land/r/gnoswap/referral/v1
gno 0.9 doc.gno gno
⧉
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 // ContractAddress () string
GetLastOpTimestamp (addr string) (int64, interface {Error func() string})
GetReferral (addr string) string
HasReferral (addr string) bool
IsEmpty () bool
NewKeeper () interface {get func(.uverse.address) (.uverse.address, .uverse.error); getLastOpTimestamp func(.uverse.address) (int64, .uverse.error); has func(.uverse.address) bool; isEmpty func() bool; register func(.uverse.address, .uverse.address) (.uverse.address, .uverse.error)}
Render (path string) string
TryRegister (cur interface {.seal func(); Address func() .uverse.address; IsCode func() bool; IsCurrent func() bool; IsEphemeral func() bool; IsUser func() bool; IsUserCall func() bool; IsUserRun func() bool; PkgPath func() string; Previous func() .uverse.realm; String func() string; Sub func(string) .uverse.realm; Subpath func() string}, addr string, referral string) string
Signatures reconstructed verbatim from vm/qfuncs — interface params keep their inline definitions.
vm/qrender output, sanitized (docs/render-security.md) and displayed in an empty-sandbox iframe — scripts, forms and popups cannot run. Links stay inert in-preview; right-click to open.
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.
151 package referral
152