Smart Contract

FlowVaultsClosedBeta

A.b1d63873c3cc9f79.FlowVaultsClosedBeta

Valid From

131,794,173

Deployed

1w ago
Feb 19, 2026, 10:35:24 AM UTC

Dependents

25 imports
1access(all) contract FlowVaultsClosedBeta {
2
3    access(all) entitlement Admin
4    access(all) entitlement Beta
5
6    access(all) resource BetaBadge {
7        access(all) let assignedTo: Address
8        init(_ addr: Address) {
9            self.assignedTo = addr
10        }
11        access(all) view fun getOwner(): Address {
12            return self.assignedTo
13        }
14    }
15
16    // --- Paths ---
17    access(all) let UserBetaCapStoragePath: StoragePath
18    access(all) let AdminHandleStoragePath: StoragePath
19
20    // --- Registry: which capability was issued to which address, and revocation flags ---
21    access(all) struct AccessInfo {
22        access(all) let capID: UInt64
23        access(all) let isRevoked: Bool
24
25        init(_ capID: UInt64, _ isRevoked: Bool) {
26            self.capID = capID
27            self.isRevoked = isRevoked
28        }
29    }
30    access(all) var issuedCapIDs: {Address: AccessInfo}
31
32    // --- Events ---
33    access(all) event BetaGranted(addr: Address, capID: UInt64)
34    access(all) event BetaRevoked(addr: Address, capID: UInt64?)
35
36    /// Per-user badge storage path (under the *contract/deployer* account)
37    access(contract) fun _badgePath(_ addr: Address): StoragePath {
38        return StoragePath(identifier: "TY_BetaBadge_".concat(addr.toString()))!
39    }
40
41    /// Ensure the admin-owned badge exists for the user
42    access(contract) fun _ensureBadge(_ addr: Address) {
43        let p = self._badgePath(addr)
44        if self.account.storage.type(at: p) == nil {
45            self.account.storage.save(<-create BetaBadge(addr), to: p)
46        }
47    }
48
49    access(contract) fun _destroyBadge(_ addr: Address) {
50        let p = self._badgePath(addr)
51        if let badge <- self.account.storage.load<@BetaBadge>(from: p) {
52            destroy badge
53        }
54    }
55
56    /// Issue a capability from the contract/deployer account and record its ID
57    access(contract) fun _issueBadgeCap(_ addr: Address): Capability<auth(Beta) &BetaBadge> {
58        let p = self._badgePath(addr)
59        let cap: Capability<auth(Beta) &BetaBadge> =
60            self.account.capabilities.storage.issue<auth(Beta) &BetaBadge>(p)
61
62        self.issuedCapIDs[addr] = AccessInfo(cap.id, false)
63
64        if let ctrl = self.account.capabilities.storage.getController(byCapabilityID: cap.id) {
65            ctrl.setTag("flowvaults-beta")
66        }
67
68        emit BetaGranted(addr: addr, capID: cap.id)
69        return cap
70    }
71
72    /// Delete the recorded controller, revoking *all copies* of the capability
73    access(contract) fun _revokeByAddress(_ addr: Address) {
74        let info = self.issuedCapIDs[addr] ?? panic("No cap recorded for address")
75        let ctrl = self.account.capabilities.storage.getController(byCapabilityID: info.capID)
76            ?? panic("Missing controller for recorded cap ID")
77        ctrl.delete()
78        self.issuedCapIDs[addr] = AccessInfo(info.capID, true)
79        self._destroyBadge(addr)
80        emit BetaRevoked(addr: addr, capID: info.capID)
81    }
82
83    // 2) A small in-account helper resource that performs privileged ops
84    access(all) resource AdminHandle {
85        access(Admin) fun grantBeta(addr: Address): Capability<auth(FlowVaultsClosedBeta.Beta) &FlowVaultsClosedBeta.BetaBadge> {
86            FlowVaultsClosedBeta._ensureBadge(addr)
87            return FlowVaultsClosedBeta._issueBadgeCap(addr)
88        }
89
90        access(Admin) fun revokeByAddress(addr: Address) {
91            FlowVaultsClosedBeta._revokeByAddress(addr)
92        }
93    }
94
95    /// Read-only check used by any gated entrypoint
96    access(all) view fun getBetaCapID(_ addr: Address): UInt64? {
97        if let info = self.issuedCapIDs[addr] {
98            if info.isRevoked {
99                assert(info.isRevoked, message: "Beta access revoked") 
100                return nil
101            }
102            return info.capID
103        }
104        return nil
105    }
106
107    access(all) view fun validateBeta(_ addr: Address?, _ betaRef: auth(Beta) &BetaBadge): Bool {
108        if (addr == nil) {
109            assert(addr == nil, message: "Address is required for Beta verification") 
110            return false
111        }
112        let recordedID: UInt64? = self.getBetaCapID(addr!); 
113        if recordedID == nil {
114            assert(recordedID == nil, message: "No Beta access") 
115            return false
116        }
117
118        if betaRef.getOwner() != addr {
119            assert(betaRef.getOwner() != addr, message: "BetaBadge may only be used by its assigned owner") 
120            return false
121        }
122
123        return true 
124    }
125
126    init() {
127        self.AdminHandleStoragePath = StoragePath(
128            identifier: "FlowVaultsClosedBetaAdmin_\(self.account.address)"
129        )!
130        self.UserBetaCapStoragePath = StoragePath(
131            identifier: "FlowVaultsUserBetaCap_\(self.account.address)"
132        )!
133
134        self.issuedCapIDs = {}
135
136        // Create and store the admin handle in *this* (deployer) account
137        self.account.storage.save(<-create AdminHandle(), to: self.AdminHandleStoragePath)
138    }
139}
140