Smart Contract
FlowServiceAccount
A.e467b9dd11fa00df.FlowServiceAccount
1import FungibleToken from 0xf233dcee88fe0abe
2import FlowToken from 0x1654653399040a61
3import FlowFees from 0xf919ee77447b7497
4import FlowStorageFees from 0xe467b9dd11fa00df
5import FlowExecutionParameters from 0xf426ff57ee8f6110
6
7access(all) contract FlowServiceAccount {
8
9 access(all) event TransactionFeeUpdated(newFee: UFix64)
10
11 access(all) event AccountCreationFeeUpdated(newFee: UFix64)
12
13 access(all) event AccountCreatorAdded(accountCreator: Address)
14
15 access(all) event AccountCreatorRemoved(accountCreator: Address)
16
17 access(all) event IsAccountCreationRestrictedUpdated(isRestricted: Bool)
18
19 /// A fixed-rate fee charged to execute a transaction
20 access(all) var transactionFee: UFix64
21
22 /// A fixed-rate fee charged to create a new account
23 access(all) var accountCreationFee: UFix64
24
25 /// The list of account addresses that have permission to create accounts
26 access(contract) var accountCreators: {Address: Bool}
27
28 /// Initialize an account with a FlowToken Vault and publish capabilities.
29 access(all) fun initDefaultToken(_ acct: auth(SaveValue, Capabilities) &Account) {
30 // Create a new FlowToken Vault and save it in storage
31 acct.storage.save(<-FlowToken.createEmptyVault(vaultType: Type<@FlowToken.Vault>()), to: /storage/flowTokenVault)
32
33 // Create a public capability to the Vault that only exposes
34 // the deposit function through the Receiver interface
35 let receiverCapability = acct.capabilities.storage.issue<&FlowToken.Vault>(/storage/flowTokenVault)
36 acct.capabilities.publish(receiverCapability, at: /public/flowTokenReceiver)
37
38 // Create a public capability to the Vault that only exposes
39 // the balance field through the Balance interface
40 let balanceCapability = acct.capabilities.storage.issue<&FlowToken.Vault>(/storage/flowTokenVault)
41 acct.capabilities.publish(balanceCapability, at: /public/flowTokenBalance)
42 }
43
44 /// Get the default token balance on an account
45 ///
46 /// Returns 0 if the account has no default balance
47 access(all) view fun defaultTokenBalance(_ acct: &Account): UFix64 {
48 var balance = 0.0
49 if let balanceRef = acct.capabilities.borrow<&FlowToken.Vault>(/public/flowTokenBalance) {
50 balance = balanceRef.balance
51 }
52
53 return balance
54 }
55
56 /// Return a reference to the default token vault on an account
57 access(all) view fun defaultTokenVault(_ acct: auth(BorrowValue) &Account): auth(FungibleToken.Withdraw) &FlowToken.Vault {
58 return acct.storage.borrow<auth(FungibleToken.Withdraw) &FlowToken.Vault>(from: /storage/flowTokenVault)
59 ?? panic("Unable to borrow reference to the default token vault")
60 }
61
62 /// Will be deprecated and can be deleted after the switchover to FlowFees.deductTransactionFee
63 ///
64 /// Called when a transaction is submitted to deduct the fee
65 /// from the AuthAccount that submitted it
66 access(all) fun deductTransactionFee(_ acct: auth(BorrowValue) &Account) {
67 if self.transactionFee == UFix64(0) {
68 return
69 }
70
71 let tokenVault = self.defaultTokenVault(acct)
72 var feeAmount = self.transactionFee
73 if self.transactionFee > tokenVault.balance {
74 feeAmount = tokenVault.balance
75 }
76
77 let feeVault <- tokenVault.withdraw(amount: feeAmount)
78 FlowFees.deposit(from: <-feeVault)
79 }
80
81 /// - Deducts the account creation fee from a payer account.
82 /// - Inits the default token.
83 /// - Inits account storage capacity.
84 access(all) fun setupNewAccount(
85 newAccount: auth(SaveValue, BorrowValue, Capabilities) &Account,
86 payer: auth(BorrowValue) &Account
87 ) {
88
89 if !FlowServiceAccount.isAccountCreator(payer.address) {
90 panic("Account not authorized to create accounts")
91 }
92
93
94 if self.accountCreationFee < FlowStorageFees.minimumStorageReservation {
95 panic("Account creation fees setup incorrectly")
96 }
97
98 let tokenVault = self.defaultTokenVault(payer)
99 let feeVault <- tokenVault.withdraw(amount: self.accountCreationFee)
100 let storageFeeVault <- (feeVault.withdraw(amount: FlowStorageFees.minimumStorageReservation) as! @FlowToken.Vault)
101 FlowFees.deposit(from: <-feeVault)
102
103 FlowServiceAccount.initDefaultToken(newAccount)
104
105 let vaultRef = FlowServiceAccount.defaultTokenVault(newAccount)
106
107 vaultRef.deposit(from: <-storageFeeVault)
108 }
109
110 /// Returns true if the given address is permitted to create accounts, false otherwise
111 access(all) view fun isAccountCreator(_ address: Address): Bool {
112 // If account creation is not restricted, then anyone can create an account
113 if !self.isAccountCreationRestricted() {
114 return true
115 }
116 return self.accountCreators[address] ?? false
117 }
118
119 /// Is true if new acconts can only be created by approved accounts `self.accountCreators`
120 access(all) view fun isAccountCreationRestricted(): Bool {
121 return self.account.storage.copy<Bool>(from: /storage/isAccountCreationRestricted) ?? false
122 }
123
124 // Authorization resource to change the fields of the contract
125 /// Returns all addresses permitted to create accounts
126 access(all) view fun getAccountCreators(): [Address] {
127 return self.accountCreators.keys
128 }
129
130 // Gets Execution Effort Weights from the service account's storage
131 access(all) view fun getExecutionEffortWeights(): {UInt64: UInt64} {
132 return FlowExecutionParameters.getExecutionEffortWeights()
133 }
134
135 // Gets Execution Memory Weights from the service account's storage
136 access(all) view fun getExecutionMemoryWeights(): {UInt64: UInt64} {
137 return FlowExecutionParameters.getExecutionMemoryWeights()
138 }
139
140 // Gets Execution Memory Limit from the service account's storage
141 access(all) view fun getExecutionMemoryLimit(): UInt64 {
142 return FlowExecutionParameters.getExecutionMemoryLimit()
143 }
144
145 /// Authorization resource to change the fields of the contract
146 access(all) resource Administrator {
147
148 /// Sets the transaction fee
149 access(all) fun setTransactionFee(_ newFee: UFix64) {
150 if newFee != FlowServiceAccount.transactionFee {
151 emit TransactionFeeUpdated(newFee: newFee)
152 }
153 FlowServiceAccount.transactionFee = newFee
154 }
155
156 /// Sets the account creation fee
157 access(all) fun setAccountCreationFee(_ newFee: UFix64) {
158 if newFee != FlowServiceAccount.accountCreationFee {
159 emit AccountCreationFeeUpdated(newFee: newFee)
160 }
161 FlowServiceAccount.accountCreationFee = newFee
162 }
163
164 /// Adds an account address as an authorized account creator
165 access(all) fun addAccountCreator(_ accountCreator: Address) {
166 if FlowServiceAccount.accountCreators[accountCreator] == nil {
167 emit AccountCreatorAdded(accountCreator: accountCreator)
168 }
169 FlowServiceAccount.accountCreators[accountCreator] = true
170 }
171
172 /// Removes an account address as an authorized account creator
173 access(all) fun removeAccountCreator(_ accountCreator: Address) {
174 if FlowServiceAccount.accountCreators[accountCreator] != nil {
175 emit AccountCreatorRemoved(accountCreator: accountCreator)
176 }
177 FlowServiceAccount.accountCreators.remove(key: accountCreator)
178 }
179
180 access(all) fun setIsAccountCreationRestricted(_ enabled: Bool) {
181 let path = /storage/isAccountCreationRestricted
182 let oldValue = FlowServiceAccount.account.storage.load<Bool>(from: path)
183 FlowServiceAccount.account.storage.save<Bool>(enabled, to: path)
184 if enabled != oldValue {
185 emit IsAccountCreationRestrictedUpdated(isRestricted: enabled)
186 }
187 }
188 }
189
190 init() {
191 self.transactionFee = 0.0
192 self.accountCreationFee = 0.0
193
194 self.accountCreators = {}
195
196 let admin <- create Administrator()
197 admin.addAccountCreator(self.account.address)
198
199 self.account.storage.save(<-admin, to: /storage/flowServiceAdmin)
200 }
201}