Smart Contract

FlowServiceAccount

A.e467b9dd11fa00df.FlowServiceAccount

Valid From

138,301,162

Deployed

2w ago
Feb 14, 2026, 03:27:09 PM UTC

Dependents

5 imports
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}