Smart Contract
FLOATVerifiers
A.2d4c3caffbeab845.FLOATVerifiers
1// MADE BY: Emerald City, Jacob Tucker
2
3// This contract is probably the most confusing element of the FLOAT
4// platform. Listed here is a bunch of Structs which all implement
5// FLOAT.IVerifier.
6
7// This pattern allows us to define arbitrary "restrictions" or "verifiers"
8// on our FLOAT Events. For example, Timelock is a verifier that makes sure
9// the current time is within the start and end date that the FLOAT Event host
10// specified when they created an event.
11
12// The cool part is all of these verifiers are totally optional, and are only
13// passed in with the newly created event if the host wanted to enable them.
14// You can mix and match them however you want. For example, one event I could
15// use both Timelock and Limited, and for another event I could just use Secret.
16
17// Each verifier must have a `verify` function that takes in a generalized `params`
18// argument so we can pass user data through as well as info about the event itself.
19// This is important for Secret for example because we want to pass the users guess
20// of the secret code through. For Limited, we need to know the totalSupply of the event,
21// so we pass it through as well.
22
23import FLOAT from 0x2d4c3caffbeab845
24import FungibleToken from 0xf233dcee88fe0abe
25import FlowToken from 0x1654653399040a61
26import Crypto
27
28access(all) contract FLOATVerifiers {
29
30 // The "verifiers" to be used
31
32 //
33 // Timelock
34 //
35 // Specifies a time range in which the
36 // FLOAT from an event can be claimed
37 access(all) struct Timelock: FLOAT.IVerifier {
38 // An automatic switch handled by the contract
39 // to stop people from claiming after a certain time.
40 access(all) let dateStart: UFix64
41 access(all) let dateEnding: UFix64
42
43 access(account) fun verify(_ params: {String: AnyStruct}) {
44 assert(
45 getCurrentBlock().timestamp >= self.dateStart,
46 message: "This FLOAT Event has not started yet."
47 )
48 assert(
49 getCurrentBlock().timestamp <= self.dateEnding,
50 message: "Sorry! The time has run out to mint this FLOAT."
51 )
52 }
53
54 init(_dateStart: UFix64, _timePeriod: UFix64) {
55 self.dateStart = _dateStart
56 self.dateEnding = self.dateStart + _timePeriod
57 }
58 }
59
60 //
61 // Secret
62 //
63 // Specifies a secret code in order
64 // to claim a FLOAT (not very secure, but cool feature)
65 access(all) struct Secret: FLOAT.IVerifier {
66 // The secret code, set by the owner of this event.
67 access(self) let secretPhrase: String
68
69 access(account) fun verify(_ params: {String: AnyStruct}) {
70 let secretPhrase = params["secretPhrase"]! as! String
71 assert(
72 self.secretPhrase == secretPhrase,
73 message: "You did not input the correct secret phrase."
74 )
75 }
76
77 init(_secretPhrase: String) {
78 self.secretPhrase = _secretPhrase
79 }
80 }
81
82 //
83 // Limited
84 //
85 // Specifies a limit for the amount of people
86 // who can CLAIM. Not to be confused with how many currently
87 // hold a FLOAT from this event, since users can
88 // delete their FLOATs.
89 access(all) struct Limited: FLOAT.IVerifier {
90 access(all) var capacity: UInt64
91
92 access(account) fun verify(_ params: {String: AnyStruct}) {
93 let floatEvent = params["event"]! as! &FLOAT.FLOATEvent
94 let currentCapacity = floatEvent.totalSupply
95 assert(
96 currentCapacity < self.capacity,
97 message: "This FLOAT Event is at capacity."
98 )
99 }
100
101 init(_capacity: UInt64) {
102 self.capacity = _capacity
103 }
104 }
105
106 //
107 // MultipleSecret
108 //
109 // Allows for Multiple Secret codes
110 // Everytime a secret gets used, it gets removed
111 // from the list.
112 access(all) struct MultipleSecret: FLOAT.IVerifier {
113 access(self) let secrets: {String: Bool}
114
115 access(account) fun verify(_ params: {String: AnyStruct}) {
116 let secretPhrase = params["secretPhrase"]! as! String
117 assert(
118 self.secrets[secretPhrase] != nil,
119 message: "You did not input a correct secret phrase."
120 )
121 self.secrets.remove(key: secretPhrase)
122 }
123
124 init(_secrets: [String]) {
125 self.secrets = {}
126 for secret in _secrets {
127 self.secrets[secret] = true
128 }
129 }
130 }
131
132 //
133 // SecretV2
134 //
135 // Much more secure than Secret
136 access(all) struct SecretV2: FLOAT.IVerifier {
137 access(all) let publicKey: String
138
139 access(account) fun verify(_ params: {String: AnyStruct}) {
140 let data: [UInt8] = (params["claimee"]! as! Address).toString().utf8
141 let sig: [UInt8] = (params["secretSig"]! as! String).decodeHex()
142 let publicKey = PublicKey(publicKey: self.publicKey.decodeHex(), signatureAlgorithm: SignatureAlgorithm.ECDSA_P256)
143 // validates that the "sig" was what was produced by signing "data" using the private key paired to "publicKey"
144 let valid = publicKey.verify(signature: sig, signedData: data, domainSeparationTag: "FLOW-V0.0-user", hashAlgorithm: HashAlgorithm.SHA3_256)
145
146 assert(
147 valid,
148 message: "You did not input the correct secret phrase."
149 )
150 }
151
152 init(_publicKey: String) {
153 self.publicKey = _publicKey
154 }
155 }
156
157 //
158 // MinimumBalance
159 //
160 // Requires a minimum Flow Balance to succeed
161 access(all) struct MinimumBalance: FLOAT.IVerifier {
162 access(all) let amount: UFix64
163
164 access(account) fun verify(_ params: {String: AnyStruct}) {
165 let claimee: Address = params["claimee"]! as! Address
166 let flowVault = getAccount(claimee).capabilities.borrow<&FlowToken.Vault>(/public/flowTokenBalance)
167 ?? panic("Could not borrow the Flow Token Vault")
168
169 assert(
170 flowVault.balance >= self.amount,
171 message: "You do not meet the minimum required Flow Token balance."
172 )
173 }
174
175 init(_amount: UFix64) {
176 self.amount = _amount
177 }
178 }
179
180 access(all) struct ChallengeAchievementPoint: FLOAT.IVerifier {
181 access(account) fun verify(_ params: {String: AnyStruct}) {
182 panic("Deprecated")
183 }
184 }
185
186 //
187 // Email
188 //
189 // Requires an admin to sign off that a user
190 // address provided their email
191 access(all) struct Email: FLOAT.IVerifier {
192 access(all) let publicKey: String
193
194 access(account) fun verify(_ params: {String: AnyStruct}) {
195 let floatEvent = params["event"]! as! &FLOAT.FLOATEvent
196 let claimeeAddressAsString: String = (params["claimee"]! as! Address).toString()
197 let messageString: String = claimeeAddressAsString.concat(" provided email for eventId ").concat(floatEvent.eventId.toString())
198 let data: [UInt8] = messageString.utf8
199 let sig: [UInt8] = (params["emailSig"]! as! String).decodeHex()
200 let publicKey = PublicKey(publicKey: self.publicKey.decodeHex(), signatureAlgorithm: SignatureAlgorithm.ECDSA_P256)
201 // validates that the "sig" was what was produced by signing "data" using the private key paired to "publicKey"
202 let valid = publicKey.verify(signature: sig, signedData: data, domainSeparationTag: "FLOW-V0.0-user", hashAlgorithm: HashAlgorithm.SHA3_256)
203
204 assert(
205 valid,
206 message: "You did not input the correct secret phrase."
207 )
208 }
209
210 init(_publicKey: String) {
211 self.publicKey = _publicKey
212 }
213 }
214
215}