Smart Contract
PinPin
A.3d4488a67d9b07e1.PinPin
1import FlowTransactionScheduler from 0xe467b9dd11fa00df
2import FlowToken from 0x1654653399040a61
3import FungibleToken from 0xf233dcee88fe0abe
4
5access(all) contract PinPin {
6 // -----------------------------------------------------------------------
7 // PinPin contract-level fields.
8 // These contain actual values that are stored in the smart contract.
9 // -----------------------------------------------------------------------
10 access(all) var subscriptionFee: UFix64
11
12 // Events
13 access(all) event ContractInitialized()
14 access(all) event SubscriptionActivated(subscriber: Address)
15 // -----------------------------------------------------------------------
16 // PinPin account paths
17 // -----------------------------------------------------------------------
18
19 access(all) let SubscriptionStoragePath: StoragePath
20 access(all) let SubscriptionPublicPath: PublicPath
21 access(all) let handlerStoragePath: StoragePath
22
23 // access(all) let feeVaultStoragePath: StoragePath
24 // access(all) let receiptsStoragePath: StoragePath
25
26 // -----------------------------------------------------------------------
27 // PinPin contract-level Composite Type definitions
28 // -----------------------------------------------------------------------
29
30 // Subscription resource
31 // This resource is used to store the subscription information
32 access(all) resource Subscription {
33 access(all) let subscriber: Address
34 access(all) let fee: UFix64
35 access(all) let cycles: UFix64
36 access(all) let startedAt: UFix64
37 access(all) let expiresAt: UFix64
38
39 init(subscriber: Address, fee: UFix64, cycles: UFix64, startedAt: UFix64, expiresAt: UFix64) {
40 self.subscriber = subscriber
41 self.fee = fee
42 self.cycles = cycles
43 self.startedAt = startedAt
44 self.expiresAt = expiresAt
45 }
46 }
47 // Subscription manager
48 // This storage is used to store and manage the subscriptions
49 // inside a user's account
50 access(all) resource SubscriptionManager {
51 access(all) var subscriptions: @[Subscription]
52
53 init() {
54 self.subscriptions <- []
55 }
56 }
57 // -----------------------------------------------------------------------
58 /// Handler resource that implements the Scheduled Transaction interface
59 access(all) resource Handler: FlowTransactionScheduler.TransactionHandler {
60
61 access(self) var feeVault: @FlowToken.Vault
62 access(self) var receipts: @[FlowTransactionScheduler.ScheduledTransaction]
63
64 access(FlowTransactionScheduler.Execute) fun executeTransaction(id: UInt64, data: AnyStruct?) {
65 // Get PinPin's Flow vault ref
66 let pinPinVault = PinPin.account.capabilities.borrow<&{FungibleToken.Receiver}>(/public/flowTokenReceiver)!
67 // Get a reference to the vaultCap
68 // let ref <- self.feeVault.withdraw(amount: 0.1)
69 // Deposit 0 Flow on the PinPin account
70 pinPinVault.deposit(from: <- self.feeVault.withdraw(amount: 0.1))
71 log("Account /self.owner!.address has made a deposit for a subscription")
72 emit SubscriptionActivated(subscriber: self.owner!.address)
73 // Determine delay for the next transaction (default 3 seconds if none provided)
74 var delay: UFix64 = 60.0
75 if data != nil {
76 let t = data!.getType()
77 if t.isSubtype(of: Type<UFix64>()) {
78 delay = data as! UFix64
79 }
80 }
81
82 let future = getCurrentBlock().timestamp + delay
83 let priority = FlowTransactionScheduler.Priority.Medium
84 let executionEffort: UInt64 = 1000
85
86 let estimate = FlowTransactionScheduler.estimate(
87 data: data,
88 timestamp: future,
89 priority: priority,
90 executionEffort: executionEffort
91 )
92
93 assert(
94 estimate.timestamp != nil || priority == FlowTransactionScheduler.Priority.Low,
95 message: estimate.error ?? "estimation failed"
96 )
97
98 // Withdraw FLOW fees from this resource's ownner account vault
99 let fees <- self.feeVault.withdraw(amount: estimate.flowFee ?? 0.0) as! @FlowToken.Vault
100
101 // Issue a capability to the handler stored in this contract account
102 let handlerCap = PinPin.account.capabilities.storage
103 .issue<auth(FlowTransactionScheduler.Execute) &{FlowTransactionScheduler.TransactionHandler}>(/storage/PinPin)
104
105 let receipt: @FlowTransactionScheduler.ScheduledTransaction <- FlowTransactionScheduler.schedule(
106 handlerCap: handlerCap,
107 data: data,
108 timestamp: future,
109 priority: priority,
110 executionEffort: executionEffort,
111 fees: <-fees
112 )
113
114 log("Loop transaction id: ".concat(receipt.id.toString()).concat(" at ").concat(receipt.timestamp.toString()))
115
116 destroy receipt
117 }
118
119 init(_ vault: @FlowToken.Vault,_ consentedFee: UFix64,_ consentedCycles: UFix64) {
120 pre {
121 PinPin.subscriptionFee == consentedFee: "Consented fee must be equal to contract's current fee"
122 vault.balance >= consentedCycles * consentedFee: "Vault's balance must be equal or greater than Fees x Cycles"
123 }
124 self.feeVault <- vault
125 self.receipts <- []
126 }
127 }
128
129 /// Factory for the handler resource
130 access(all) fun createHandler(vault: @FlowToken.Vault, consentedFee: UFix64, consentedCycles: UFix64): @Handler {
131 return <- create Handler(<- vault, consentedFee, consentedCycles)
132 }
133
134 init() {
135 self.subscriptionFee = 0.1
136
137 // Set the named paths
138 let identifier = "PinPin_".concat(self.account.address.toString())
139 self.SubscriptionStoragePath = StoragePath(identifier: identifier)!
140 self.SubscriptionPublicPath = PublicPath(identifier: identifier)!
141 self.handlerStoragePath = StoragePath(identifier: identifier)!
142 emit ContractInitialized()
143 }
144}