Search Apps Documentation Source Content File Folder Download Copy Actions Download

referral package

Overview

Package referral implements a referral system on Gno. It allows authorized contracts to register, update, or remove referral relationships. A referral link is defined as a mapping from one address (the "user") to another address (the "referrer"). \## Overview The referral package is composed of the following components: 1. \*\*errors.gno\*\*: Defines error types for various failure scenarios such as invalid address, unauthorized caller, self-referral, rate limit exceeded, and referral not found. 2. \*\*utils.gno\*\*: Contains the isValidCaller function that checks if the caller has an authorized role (governance, router, position, staker, or launchpad contracts). 3. \*\*type.gno\*\*: Defines the ReferralKeeper interface and event type constants for register, update, and remove operations. 4. \*\*keeper.gno\*\*: Implements the ReferralKeeper interface using an AVL tree for storage. Includes rate limiting (24-hour cooldown) to prevent abuse of referral operations. 5. \*\*global\_keeper.gno\*\*: Exposes the public API functions that external contracts can use to interact with the referral system. \## Public API The package exposes the following public functions: - GetReferral(addr string) string: Returns the referrer address for the given user address. Returns empty string if not found. - HasReferral(addr string) bool: Returns true if the user has a registered referrer. - IsEmpty() bool: Returns true if no referral relationships exist. - GetLastOpTimestamp(addr string) (int64, error): Returns the last referral operation timestamp for the given user address. - TryRegister(cur realm, addr address, referral string) bool: Attempts to register a new referral. Returns true on success. \## Workflow Typical usage of this contract follows these steps: 1. An authorized contract (router, staker, etc.) calls TryRegister to create a referral relationship. 2. The keeper validates the caller's permissions via isValidCaller. 3. Address validation ensures both addresses are valid and not self-referencing. 4. Rate limiting checks prevent operations more than once per 24 hours. 5. The referral is stored in the AVL tree and an event is emitted. \## Authorized Callers Only contracts with the following roles can modify referral data: - ROLE\_GOVERNANCE: Governance contracts - ROLE\_GOV\_STAKER: Governance staker contracts - ROLE\_ROUTER: Router contracts - ROLE\_POSITION: Position manager contracts - ROLE\_STAKER: Staker contracts - ROLE\_LAUNCHPAD: Launchpad contracts \## Rate Limiting To prevent abuse, the system enforces a 24-hour cooldown period between operations for each address. This means: - A new referral can only be registered once per 24 hours per address - Updates and removals are also subject to the same rate limit - Attempting operations within the cooldown period returns ErrTooManyRequests \## Events The package emits the following events: - RegisterReferral: Emitted when a new referral is created - ReferralRegistrationFailed: Emitted when TryRegister fails \## Error Handling The package defines several error types: - \`ErrInvalidAddress\`: Returned when an address format is invalid - \`ErrSelfReferral\`: Returned when attempting to set self as referrer - \`ErrUnauthorized\`: Returned when the caller lacks permission - \`ErrTooManyRequests\`: Returned when rate limit is exceeded (24-hour cooldown) - \`ErrNotFound\`: Returned when attempting to get a non-existent referral - \`ErrInvalidTime\`: Returned when the stored timestamp format is invalid \## Example: Integration with Router Contract The router contract can register referrals during swap operations: \`\`\`go import ( "chain/runtime" "gno.land/r/gnoswap/referral" ) func SwapWithReferral(cur realm, referralCode string, ...) { // Get the caller address caller := runtime.PreviousRealm().Address() // Register the referral if provided if referralCode != "" { success := referral.TryRegister(cross, caller, referralCode) actualReferrer := referralCode if !success { // Get existing referral if registration failed actualReferrer = referral.GetReferral(caller.String()) } } // Continue with swap logic... } \`\`\` \## Example: Checking Referral for Rewards Other contracts can check referral relationships for reward distribution: \`\`\`go import ( "gno.land/r/gnoswap/referral" ) func DistributeRewards(user address, amount uint64) { // Check if user has a referrer if referral.HasReferral(user.String()) { referrerAddr := referral.GetReferral(user.String()) // Calculate and distribute referral bonus referrerBonus := amount * referralRate / 100 sendReward(address(referrerAddr), referrerBonus) } } \`\`\` \## Limitations and Constraints - A user can have only one referrer at a time - Self-referral is not allowed - Operations are rate-limited to once per 24 hours per address - Only authorized contracts can register/update/remove referrals - Zero address as referrer triggers removal of the referral \## Notes - The contract uses RBAC (Role-Based Access Control) for authorization - Rate limiting state persists across transactions - Events are emitted for all state changes for off-chain tracking

Functions

ContractAddress

func ContractAddress() string

ContractAddress returns the address of the referral contract. Use this address as the referral parameter in TryRegister to remove an existing referral.

Command

gnokey query vm/qeval -remote "https://rpc.test11.testnets.gno.land" -data "gno.land/r/gnoswap/referral.ContractAddress()"

Result

GetLastOpTimestamp

func GetLastOpTimestamp(addr string) (int64, error)

GetLastOpTimestamp returns the last operation timestamp for the given address. Returns ErrNotFound if no operation exists.

Param

Command

gnokey query vm/qeval -remote "https://rpc.test11.testnets.gno.land" -data "gno.land/r/gnoswap/referral.GetLastOpTimestamp()"

Result

GetReferral

func GetReferral(addr string) string

GetReferral returns the referral address for the given address.

Param

Command

gnokey query vm/qeval -remote "https://rpc.test11.testnets.gno.land" -data "gno.land/r/gnoswap/referral.GetReferral()"

Result

HasReferral

func HasReferral(addr string) bool

HasReferral returns true if the given address has a referral.

Param

Command

gnokey query vm/qeval -remote "https://rpc.test11.testnets.gno.land" -data "gno.land/r/gnoswap/referral.HasReferral()"

Result

IsEmpty

func IsEmpty() bool

IsEmpty returns true if no referrals exist in the system.

Command

gnokey query vm/qeval -remote "https://rpc.test11.testnets.gno.land" -data "gno.land/r/gnoswap/referral.IsEmpty()"

Result

TryRegister

func TryRegister(cur realm, addr address, referral string) bool

TryRegister attempts to register a new referral. Parameters: - addr: address to register - referral: referral address string Returns true on success, false on failure. Panics if the caller is not authorized.

Params

Command

# WARNING: This command is running in an INSECURE mode.
# It is strongly recommended to use a hardware device for signing
# and avoid trusting any computer connected to the internet,
# as your private keys could be exposed.

gnokey maketx call -pkgpath "gno.land/r/gnoswap/referral" -func "TryRegister" -args $'' -args $'' -gas-fee 1000000ugnot -gas-wanted 5000000 -send "" -broadcast -chainid "test11" -remote "https://rpc.test11.testnets.gno.land" ADDRESSgnokey query -remote "https://rpc.test11.testnets.gno.land" auth/accounts/ADDRESS
gnokey maketx call -pkgpath "gno.land/r/gnoswap/referral" -func "TryRegister" -args $'' -args $'' -gas-fee 1000000ugnot -gas-wanted 5000000 -send "" ADDRESS > call.tx
gnokey sign -tx-path call.tx -chainid "test11" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER ADDRESS
gnokey broadcast -remote "https://rpc.test11.testnets.gno.land" call.tx
  

NewKeeper

func NewKeeper() ReferralKeeper

NewKeeper creates a new ReferralKeeper instance.

Command

gnokey query vm/qeval -remote "https://rpc.test11.testnets.gno.land" -data "gno.land/r/gnoswap/referral.NewKeeper()"

Result