Smart Contract

RV3

A.3ddb31a3880d1d8f.RV3

Deployed

1d ago
Feb 26, 2026, 10:41:48 PM UTC

Dependents

0 imports
1/**
2
3# Contract for managing on-chain referral relationships.
4
5# Author: Increment Labs
6
7*/
8
9import LendingInterfaces from 0x2df970b6cdee5735
10
11pub contract RV3 {
12    // Struct to hold referee information, including the referee's address and the timestamp when they were bound.
13    access(all) struct RefereeInfo {
14        access(all) let refereeAddr: Address
15        access(all) let bindTimestamp: UFix64
16        init(_ addr: Address, _ timestamp: UFix64) {
17            self.refereeAddr = addr
18            self.bindTimestamp = timestamp
19        }
20    }
21    
22    // A dictionary mapping referrers to an array of RefereeInfo, tracking all referees bound to each referrer.
23    // {Referrer : {Referee: BindingTime} }
24    access(self) let _referrerToReferees: {Address: [RefereeInfo]}
25
26    // A dictionary mapping referees to their respective referrers, allowing for lookup of a referee's referrer.
27    // {Referee: Referrer}
28    access(self) let _refereeToReferrer: {Address: Address}
29
30    /// Events
31    access(all) event BindingReferrer(referrer: Address, referee: Address, indexer: Int)
32
33    // Function to bind a referee to a referrer.
34    // Requires the referrer's address and a capability to fetch the referee's address from an identity certificate.
35    access(all) fun bind(referrer: Address, refereeCertificateCap: Capability<&{LendingInterfaces.IdentityCertificate}>) {
36        let referee: Address = refereeCertificateCap.borrow()!.owner!.address
37
38        assert(self._refereeToReferrer.containsKey(referee) == false, message: "Referrer already bound")
39        assert(referee != referrer, message: "Can't bind yourself")
40
41        self._refereeToReferrer[referee] = referrer
42        if self._referrerToReferees.containsKey(referrer) == false {
43            self._referrerToReferees[referrer] = []
44        }
45        self._referrerToReferees[referrer]!.append(RefereeInfo(referee, getCurrentBlock().timestamp))
46
47        // Prevent circular binding
48        //assert(self.checkCirularBinding(referee: referee) == false, message: "Cirular Binding")
49        
50        emit BindingReferrer(referrer: referrer, referee: referee, indexer: self._referrerToReferees[referrer]!.length)
51    }
52
53    // Function to check for circular bindings in the referral structure.
54    access(self) fun checkCirularBinding(referee: Address): Bool {
55        let checkedAddrs: {Address: Bool} = {referee: true}
56        var i = 0
57        var addr = referee
58        while i < 32 {
59            if self._refereeToReferrer.containsKey(addr) == false {
60                return false
61            }
62            let nextAddr = self._refereeToReferrer[addr]!
63            if checkedAddrs.containsKey(nextAddr) == true {
64                return true
65            }
66            checkedAddrs[nextAddr] = true
67            addr = nextAddr
68            i = i + 1
69        }
70        return false
71    }
72
73    access(all) fun getReferrerByReferee(referee: Address): Address? {
74        if self._refereeToReferrer.containsKey(referee) == false {
75            return nil
76        }
77        return self._refereeToReferrer[referee]!
78    }
79
80    access(all) view fun getReferrerCount(): Int {
81        return self._referrerToReferees.length
82    }
83
84    access(all) view fun getSlicedReferrerList(from: Int, to: Int): [Address] {
85        let len = self._referrerToReferees.length
86        let upTo = to > len ? len : to
87        return self._referrerToReferees.keys.slice(from: from, upTo: upTo)
88    }
89
90    access(all) view fun getRefereeCountByReferrer(referrer: Address): Int {
91        return self._referrerToReferees.containsKey(referrer) ? self._referrerToReferees[referrer]!.length : 0
92    }
93
94    access(all) view fun getSlicedRefereesByReferrer(referrer: Address, from: Int, to: Int): [RefereeInfo] {
95        if self._referrerToReferees.containsKey(referrer) == false {
96            return []
97        }
98        let len = self._referrerToReferees[referrer]!.length
99        let endIndex = to > len ? len : to
100        return self._referrerToReferees[referrer]!.slice(from: from, upTo: endIndex)
101    }
102
103    /// Admin
104    ///
105    access(all) resource Admin {
106
107    }
108
109    init() {
110        self._referrerToReferees = {}
111        self._refereeToReferrer = {}
112
113        destroy <-self.account.load<@AnyResource>(from: /storage/referralAdmin)
114        self.account.save(<-create Admin(), to: /storage/referralAdmin)
115    }
116}
117