Smart Contract

ToucansLockTokens

A.577a3c409c5dcb5e.ToucansLockTokens

Deployed

1d ago
Feb 26, 2026, 10:26:44 PM UTC

Dependents

0 imports
1import FungibleToken from 0xf233dcee88fe0abe
2import ToucansTokens from 0x577a3c409c5dcb5e
3
4access(all) contract ToucansLockTokens {
5
6    access(all) entitlement ManagerOwner
7
8    access(all) struct LockedVaultDetails {
9        access(all) let lockedVaultUuid: UInt64
10        access(all) let recipient: Address
11        access(all) let vaultType: Type
12        access(all) let unlockTime: UFix64
13        access(all) let tokenInfo: ToucansTokens.TokenInfo
14        access(all) let amount: UFix64
15        access(all) let extra: {String: AnyStruct}
16
17        init(
18            lockedVaultUuid: UInt64,
19            recipient: Address, 
20            vaultType: Type, 
21            unlockTime: UFix64, 
22            tokenInfo: ToucansTokens.TokenInfo, 
23            amount: UFix64
24        ) {
25            self.lockedVaultUuid = lockedVaultUuid
26            self.recipient = recipient
27            self.vaultType = vaultType
28            self.unlockTime = unlockTime
29            self.tokenInfo = tokenInfo
30            self.amount = amount
31            self.extra = {}
32        }
33    }
34
35    access(all) resource LockedVault {
36        access(all) let details: LockedVaultDetails
37        access(contract) var vault: @{FungibleToken.Vault}?
38        // for extra metadata
39        access(self) var additions: @{String: AnyResource}
40
41        access(contract) fun withdrawVault(receiver: &{FungibleToken.Receiver}) {
42            pre {
43                receiver.owner!.address == self.details.recipient: "This LockedVault does not belong to the receiver."
44                getCurrentBlock().timestamp >= self.details.unlockTime: "This LockedVault is not ready to be unlocked."
45            }
46            let vault <- self.vault <- nil
47            receiver.deposit(from: <- vault!)
48        }
49
50        init(recipient: Address, unlockTime: UFix64, vault: @{FungibleToken.Vault}, tokenInfo: ToucansTokens.TokenInfo) {
51            self.details = LockedVaultDetails(
52                lockedVaultUuid: self.uuid,
53                recipient: recipient, 
54                vaultType: vault.getType(), 
55                unlockTime: unlockTime, 
56                tokenInfo: tokenInfo, 
57                amount: vault.balance
58            )
59            self.vault <- vault
60            self.additions <- {}
61        }
62    }
63
64    access(all) resource interface ManagerPublic {}
65
66    access(all) resource Manager: ManagerPublic {
67        access(self) let lockedVaults: @{UInt64: LockedVault}
68        access(self) let addressMap: {Address: [UInt64]}
69        // for extra metadata
70        access(self) var additions: @{String: AnyResource}
71
72        access(ManagerOwner) fun deposit(recipient: Address, unlockTime: UFix64, vault: @{FungibleToken.Vault}, tokenInfo: ToucansTokens.TokenInfo) {
73            pre {
74                tokenInfo.tokenType == vault.getType(): "Types are not the same"
75            }
76            let lockedVault: @LockedVault <- create LockedVault(recipient: recipient, unlockTime: unlockTime, vault: <- vault, tokenInfo: tokenInfo)
77            let recipient: Address = lockedVault.details.recipient
78            if self.addressMap[recipient] == nil {
79                self.addressMap[recipient] = [lockedVault.uuid]
80            } else {
81                self.addressMap[recipient]!.append(lockedVault.uuid)
82            }
83
84            self.lockedVaults[lockedVault.uuid] <-! lockedVault
85        }
86
87        access(all) fun claim(lockedVaultUuid: UInt64, receiver: &{FungibleToken.Receiver}) {
88            let lockedVault: @LockedVault <- self.lockedVaults.remove(key: lockedVaultUuid) ?? panic("This LockedVault does not exist.")
89            lockedVault.withdrawVault(receiver: receiver)
90            assert(lockedVault.vault == nil, message: "The withdraw did not execute correctly.")
91            destroy lockedVault
92            let indexOfUuid: Int = self.addressMap[receiver.owner!.address]!.firstIndex(of: lockedVaultUuid)!
93            self.addressMap[receiver.owner!.address]!.remove(at: indexOfUuid)
94        }
95
96        access(all) view fun getIDs(): [UInt64] {
97            return self.lockedVaults.keys
98        }
99
100        access(all) view fun getIDsForAddress(address: Address): [UInt64] {
101            return self.addressMap[address] ?? []
102        }
103
104        access(all) fun getLockedVaultInfos(): [LockedVaultDetails] {
105            let ids: [UInt64] = self.getIDs()
106            let vaults: [LockedVaultDetails] = []
107            for id in ids {
108                vaults.append(self.lockedVaults[id]?.details!)
109            }
110            return vaults
111        }
112
113        access(all) fun getLockedVaultInfosForAddress(address: Address): [LockedVaultDetails] {
114            let ids: [UInt64] = self.getIDsForAddress(address: address)
115            let vaults: [LockedVaultDetails] = []
116            for id in ids {
117                vaults.append(self.lockedVaults[id]?.details!)
118            }
119            return vaults
120        }
121
122        init() {
123            self.lockedVaults <- {}
124            self.addressMap = {}
125            self.additions <- {}
126        }
127    }
128
129    access(all) fun createManager(): @Manager {
130        return <- create Manager()
131    }
132}