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 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) string: Attempts to register a new referral and returns the effective referrer. Empty input returns the user's stored referral without attempting registration.

## Workflow

Typical usage of this contract follows these steps:

  1. An authorized contract (router, staker, etc.) calls TryRegister to resolve the effective referrer and optionally 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 tree and an event is emitted when registration occurs.

## 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 non-empty referral registration 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

Example
 1import (
 2    "gno.land/r/gnoswap/referral"
 3)
 4
 5func SwapWithReferral(cur realm, referralCode string, ...) {
 6    // Get the caller address
 7    caller := cur.Previous().Address()
 8
 9    actualReferrer := referral.TryRegister(cross(cur), caller, referralCode)
10
11    // Continue with swap logic...
12}

```

## Example: Checking Referral for Rewards

Other contracts can check referral relationships for reward distribution:

```go

Example
 1import (
 2    "gno.land/r/gnoswap/referral"
 3)
 4
 5func DistributeRewards(user address, amount uint64) {
 6    // Check if user has a referrer
 7    if referral.HasReferral(user.String()) {
 8        referrerAddr := referral.GetReferral(user.String())
 9        // Calculate and distribute referral bonus
10        referrerBonus := amount * referralRate / 100
11        sendReward(address(referrerAddr), referrerBonus)
12    }
13}

```

## 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.test13.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.test13.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.test13.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.test13.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.test13.testnets.gno.land" -data "gno.land/r/gnoswap/referral.IsEmpty()"

Result

TryRegister

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

TryRegister attempts to register a new referral.

Parameters:

  • addr: address to register
  • referral: referral address string

Returns the effective referrer after applying registration or fallback. Empty input is treated as "no new referrer provided" and returns the stored referrer without attempting registration. Panics if the caller is not authorized for non-empty registration attempts.

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 1_000_000_000 -send "" -chainid "test-13" -remote "https://rpc.test13.testnets.gno.land" ADDRESSgnokey query -remote "https://rpc.test13.testnets.gno.land" auth/accounts/ADDRESS
gnokey maketx call -pkgpath "gno.land/r/gnoswap/referral" -func "TryRegister" -args $'' -args $'' -gas-fee 1000000ugnot -gas-wanted 1_000_000_000 -send "" -broadcast=false ADDRESS > call.tx
gnokey sign -tx-path call.tx -chainid "test-13" -account-number ACCOUNTNUMBER -account-sequence SEQUENCENUMBER ADDRESS
gnokey broadcast -remote "https://rpc.test13.testnets.gno.land" call.tx
  

NewKeeper

func NewKeeper() ReferralKeeper

NewKeeper creates a new ReferralKeeper instance.

Command

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

Result