github.com/onflow/flow-go@v0.33.17/fvm/systemcontracts/system_contracts.go (about) 1 // Package systemcontracts stores canonical address locations for all system 2 // smart contracts and service events. 3 // 4 // System contracts are special smart contracts controlled by the service account, 5 // a Flow account with special privileges to administer the network. 6 // 7 // Service events are special events defined within system contracts which 8 // are included within execution receipts and processed by the consensus committee 9 // to enable message-passing to the protocol state. 10 // 11 // For transient networks, all system contracts can be deployed to the service 12 // account. For long-lived networks, system contracts are spread across several 13 // accounts for historical reasons. 14 package systemcontracts 15 16 import ( 17 "fmt" 18 19 "github.com/onflow/flow-core-contracts/lib/go/templates" 20 21 "github.com/onflow/flow-go/model/flow" 22 ) 23 24 const ( 25 // Unqualified names of system smart contracts (not including address prefix) 26 27 ContractNameEpoch = "FlowEpoch" 28 ContractNameIDTableStaking = "FlowIDTableStaking" 29 ContractNameClusterQC = "FlowClusterQC" 30 ContractNameDKG = "FlowDKG" 31 ContractNameServiceAccount = "FlowServiceAccount" 32 ContractNameFlowFees = "FlowFees" 33 ContractNameStorageFees = "FlowStorageFees" 34 ContractNameNodeVersionBeacon = "NodeVersionBeacon" 35 ContractNameRandomBeaconHistory = "RandomBeaconHistory" 36 ContractNameFungibleToken = "FungibleToken" 37 ContractNameFlowToken = "FlowToken" 38 ContractNameNonFungibleToken = "NonFungibleToken" 39 ContractNameMetadataViews = "MetadataViews" 40 ContractNameViewResolver = "ViewResolver" 41 ContractNameEVM = "EVM" 42 43 // AccountNameEVMStorage is not a contract, but a special account that is used to store EVM state 44 AccountNameEVMStorage = "EVMStorageAccount" 45 46 // Unqualified names of service events (not including address prefix or contract name) 47 48 EventNameEpochSetup = "EpochSetup" 49 EventNameEpochCommit = "EpochCommit" 50 EventNameVersionBeacon = "VersionBeacon" 51 52 // Unqualified names of service event contract functions (not including address prefix or contract name) 53 54 ContractServiceAccountFunction_setupNewAccount = "setupNewAccount" 55 ContractServiceAccountFunction_defaultTokenBalance = "defaultTokenBalance" 56 ContractServiceAccountFunction_deductTransactionFee = "deductTransactionFee" 57 ContractServiceAccountFunction_verifyPayersBalanceForTransactionExecution = "verifyPayersBalanceForTransactionExecution" 58 ContractStorageFeesFunction_calculateAccountCapacity = "calculateAccountCapacity" 59 ContractStorageFeesFunction_getAccountsCapacityForTransactionStorageCheck = "getAccountsCapacityForTransactionStorageCheck" 60 ContractStorageFeesFunction_defaultTokenAvailableBalance = "defaultTokenAvailableBalance" 61 62 // Indexes of the system contracts that are deployed to an address at a specific index 63 64 FungibleTokenAccountIndex = 2 65 FlowTokenAccountIndex = 3 66 FlowFeesAccountIndex = 4 67 EVMStorageAccountIndex = 5 68 ) 69 70 // Well-known addresses for system contracts on long-running networks. 71 // For now, all system contracts tracked by this package are deployed to the same 72 // address (per chain) as the staking contract. 73 // 74 // Ref: https://docs.onflow.org/core-contracts/staking-contract-reference/ 75 var ( 76 // stakingContractAddressMainnet is the address of the FlowIDTableStaking contract on Mainnet 77 stakingContractAddressMainnet = flow.HexToAddress("8624b52f9ddcd04a") 78 // stakingContractAddressTestnet is the address of the FlowIDTableStaking contract on Testnet 79 stakingContractAddressTestnet = flow.HexToAddress("9eca2b38b18b5dfe") 80 81 // nftTokenAddressTestnet is the address of the NonFungibleToken contract on Testnet 82 nftTokenAddressMainnet = flow.HexToAddress("1d7e57aa55817448") 83 // nftTokenAddressTestnet is the address of the NonFungibleToken contract on Testnet 84 nftTokenAddressTestnet = flow.HexToAddress("631e88ae7f1d7c20") 85 86 // evmStorageAddressTestnet is the address of the EVM state storage contract on Testnet 87 evmStorageAddressTestnet = flow.HexToAddress("1a54ed2be7552821") 88 // evmStorageAddressMainnet is the address of the EVM state storage contract on Mainnet 89 evmStorageAddressMainnet = flow.HexToAddress("d421a63faae318f9") 90 ) 91 92 // SystemContract represents a system contract on a particular chain. 93 type SystemContract struct { 94 Address flow.Address 95 Name string 96 } 97 98 // SystemAccount represents an address used by the system. 99 type SystemAccount struct { 100 Address flow.Address 101 Name string 102 } 103 104 // ServiceEvent represents a service event on a particular chain. 105 type ServiceEvent struct { 106 Address flow.Address 107 ContractName string 108 Name string 109 } 110 111 // QualifiedIdentifier returns the Cadence qualified identifier of the service 112 // event, which includes the contract name and the event type name. 113 func (se ServiceEvent) QualifiedIdentifier() string { 114 return fmt.Sprintf("%s.%s", se.ContractName, se.Name) 115 } 116 117 // EventType returns the full event type identifier, including the address, the 118 // contract name, and the event type name. 119 func (se ServiceEvent) EventType() flow.EventType { 120 return flow.EventType(fmt.Sprintf("A.%s.%s.%s", se.Address, se.ContractName, se.Name)) 121 } 122 123 // SystemContracts is a container for all system contracts on a particular chain. 124 type SystemContracts struct { 125 // epoch related contracts 126 Epoch SystemContract 127 IDTableStaking SystemContract 128 ClusterQC SystemContract 129 DKG SystemContract 130 131 // service account related contracts 132 FlowServiceAccount SystemContract 133 NodeVersionBeacon SystemContract 134 RandomBeaconHistory SystemContract 135 FlowStorageFees SystemContract 136 137 // token related contracts 138 FlowFees SystemContract 139 FlowToken SystemContract 140 FungibleToken SystemContract 141 142 // NFT related contracts 143 NonFungibleToken SystemContract 144 MetadataViews SystemContract 145 ViewResolver SystemContract 146 147 // EVM related contracts 148 EVMContract SystemContract 149 EVMStorage SystemAccount 150 } 151 152 // AsTemplateEnv returns a template environment with all system contracts filled in. 153 // This is useful for generating Cadence code from templates. 154 func (c SystemContracts) AsTemplateEnv() templates.Environment { 155 return templates.Environment{ 156 EpochAddress: c.Epoch.Address.Hex(), 157 IDTableAddress: c.IDTableStaking.Address.Hex(), 158 QuorumCertificateAddress: c.ClusterQC.Address.Hex(), 159 DkgAddress: c.DKG.Address.Hex(), 160 161 ServiceAccountAddress: c.FlowServiceAccount.Address.Hex(), 162 NodeVersionBeaconAddress: c.NodeVersionBeacon.Address.Hex(), 163 RandomBeaconHistoryAddress: c.RandomBeaconHistory.Address.Hex(), 164 StorageFeesAddress: c.FlowStorageFees.Address.Hex(), 165 166 FlowFeesAddress: c.FlowFees.Address.Hex(), 167 FlowTokenAddress: c.FlowToken.Address.Hex(), 168 FungibleTokenAddress: c.FungibleToken.Address.Hex(), 169 170 // The following contracts dont exist on the template env yet 171 // that is not a problem, but they are still listed here for completeness. 172 173 // NonFungibleToken: c.NonFungibleToken.Address.Hex(), 174 // MetadataViews : c.MetadataViews.Address.Hex(), 175 // ViewResolver : c.ViewResolver.Address.Hex(), 176 177 // EVMAddress: c.EVM.Address.Hex(), 178 } 179 } 180 181 // All returns all system contracts as a slice. 182 func (c SystemContracts) All() []SystemContract { 183 return []SystemContract{ 184 c.Epoch, 185 c.IDTableStaking, 186 c.ClusterQC, 187 c.DKG, 188 189 c.FlowServiceAccount, 190 c.NodeVersionBeacon, 191 c.RandomBeaconHistory, 192 c.FlowStorageFees, 193 194 c.FlowFees, 195 c.FlowToken, 196 c.FungibleToken, 197 198 c.NonFungibleToken, 199 c.MetadataViews, 200 c.ViewResolver, 201 202 c.EVMContract, 203 // EVMStorage is not included here, since it is not a contract 204 } 205 } 206 207 // ServiceEvents is a container for all service events on a particular chain. 208 type ServiceEvents struct { 209 EpochSetup ServiceEvent 210 EpochCommit ServiceEvent 211 VersionBeacon ServiceEvent 212 } 213 214 // All returns all service events as a slice. 215 func (se ServiceEvents) All() []ServiceEvent { 216 return []ServiceEvent{ 217 se.EpochSetup, 218 se.EpochCommit, 219 se.VersionBeacon, 220 } 221 } 222 223 // SystemContractsForChain returns the system contract configuration for the given chain. 224 // Panics if the chain is unknown. 225 func SystemContractsForChain(chainID flow.ChainID) *SystemContracts { 226 contracts, ok := systemContractsForChain[chainID] 227 if !ok { 228 // this is a panic, since it can only happen if the code is wrong 229 panic(fmt.Sprintf("unknown chain: %s", chainID)) 230 } 231 return contracts 232 } 233 234 var systemContractsForChain = map[flow.ChainID]*SystemContracts{} 235 236 // ServiceEventsForChain returns the service event confirmation for the given chain. 237 // Panics if the chain is unknown. 238 func ServiceEventsForChain(chainID flow.ChainID) *ServiceEvents { 239 events, ok := serviceEventsForChain[chainID] 240 if !ok { 241 // this is a panic, since it can only happen if the code is wrong 242 panic(fmt.Sprintf("unknown chain: %s", chainID)) 243 } 244 return events 245 } 246 247 var serviceEventsForChain = map[flow.ChainID]*ServiceEvents{} 248 249 var contractAddressFunc = map[string]func(id flow.ChainID) flow.Address{} 250 251 func init() { 252 253 serviceAddressFunc := func(chain flow.ChainID) flow.Address { 254 return chain.Chain().ServiceAddress() 255 } 256 257 // epoch contracts are deployed on a separate account on mainnet and testnet 258 epochAddressFunc := func(chain flow.ChainID) flow.Address { 259 switch chain { 260 case flow.Mainnet: 261 return stakingContractAddressMainnet 262 case flow.Testnet: 263 return stakingContractAddressTestnet 264 default: 265 return chain.Chain().ServiceAddress() 266 } 267 } 268 269 // some contracts are always at an address with a a predetermined index 270 nthAddressFunc := func(index uint64) func(chain flow.ChainID) flow.Address { 271 return func(chain flow.ChainID) flow.Address { 272 address, err := chain.Chain().AddressAtIndex(index) 273 if err != nil { 274 // this can only happen if the code is wrong 275 panic(fmt.Sprintf("failed to get %d address: %v", FlowFeesAccountIndex, err)) 276 } 277 return address 278 } 279 } 280 281 nftTokenAddressFunc := func(chain flow.ChainID) flow.Address { 282 switch chain { 283 case flow.Mainnet: 284 return nftTokenAddressMainnet 285 case flow.Testnet: 286 return nftTokenAddressTestnet 287 default: 288 return chain.Chain().ServiceAddress() 289 } 290 } 291 292 evmStorageEVMFunc := func(chain flow.ChainID) flow.Address { 293 switch chain { 294 case flow.Mainnet: 295 return evmStorageAddressMainnet 296 case flow.Testnet: 297 return evmStorageAddressTestnet 298 default: 299 return nthAddressFunc(EVMStorageAccountIndex)(chain) 300 } 301 } 302 303 contractAddressFunc = map[string]func(id flow.ChainID) flow.Address{ 304 ContractNameIDTableStaking: epochAddressFunc, 305 ContractNameEpoch: epochAddressFunc, 306 ContractNameClusterQC: epochAddressFunc, 307 ContractNameDKG: epochAddressFunc, 308 309 ContractNameNodeVersionBeacon: serviceAddressFunc, 310 ContractNameRandomBeaconHistory: serviceAddressFunc, 311 ContractNameServiceAccount: serviceAddressFunc, 312 ContractNameStorageFees: serviceAddressFunc, 313 314 ContractNameFlowFees: nthAddressFunc(FlowFeesAccountIndex), 315 ContractNameFungibleToken: nthAddressFunc(FungibleTokenAccountIndex), 316 ContractNameFlowToken: nthAddressFunc(FlowTokenAccountIndex), 317 318 ContractNameNonFungibleToken: nftTokenAddressFunc, 319 ContractNameMetadataViews: nftTokenAddressFunc, 320 ContractNameViewResolver: nftTokenAddressFunc, 321 322 ContractNameEVM: serviceAddressFunc, 323 AccountNameEVMStorage: evmStorageEVMFunc, 324 } 325 326 getSystemContractsForChain := func(chainID flow.ChainID) *SystemContracts { 327 328 addressOfContract := func(name string) SystemContract { 329 addressFunc, ok := contractAddressFunc[name] 330 if !ok { 331 // this is a panic, since it can only happen if the code is wrong 332 panic(fmt.Sprintf("unknown system contract name: %s", name)) 333 } 334 335 return SystemContract{ 336 Address: addressFunc(chainID), 337 Name: name, 338 } 339 } 340 341 addressOfAccount := func(name string) SystemAccount { 342 addressFunc, ok := contractAddressFunc[name] 343 if !ok { 344 // this is a panic, since it can only happen if the code is wrong 345 panic(fmt.Sprintf("unknown system account name: %s", name)) 346 } 347 348 return SystemAccount{ 349 Address: addressFunc(chainID), 350 Name: name, 351 } 352 } 353 354 contracts := &SystemContracts{ 355 Epoch: addressOfContract(ContractNameEpoch), 356 IDTableStaking: addressOfContract(ContractNameIDTableStaking), 357 ClusterQC: addressOfContract(ContractNameClusterQC), 358 DKG: addressOfContract(ContractNameDKG), 359 360 FlowServiceAccount: addressOfContract(ContractNameServiceAccount), 361 NodeVersionBeacon: addressOfContract(ContractNameNodeVersionBeacon), 362 RandomBeaconHistory: addressOfContract(ContractNameRandomBeaconHistory), 363 FlowStorageFees: addressOfContract(ContractNameStorageFees), 364 365 FlowFees: addressOfContract(ContractNameFlowFees), 366 FlowToken: addressOfContract(ContractNameFlowToken), 367 FungibleToken: addressOfContract(ContractNameFungibleToken), 368 369 NonFungibleToken: addressOfContract(ContractNameNonFungibleToken), 370 MetadataViews: addressOfContract(ContractNameMetadataViews), 371 ViewResolver: addressOfContract(ContractNameViewResolver), 372 373 EVMContract: addressOfContract(ContractNameEVM), 374 EVMStorage: addressOfAccount(AccountNameEVMStorage), 375 } 376 377 return contracts 378 } 379 380 getServiceEventsForChain := func(chainID flow.ChainID) *ServiceEvents { 381 382 event := func(contractName, eventName string) ServiceEvent { 383 addressFunc, ok := contractAddressFunc[contractName] 384 if !ok { 385 // this is a panic, since it can only happen if the code is wrong 386 panic(fmt.Sprintf("unknown system contract name: %s", contractName)) 387 } 388 389 return ServiceEvent{ 390 Address: addressFunc(chainID), 391 ContractName: contractName, 392 Name: eventName, 393 } 394 } 395 396 events := &ServiceEvents{ 397 EpochSetup: event(ContractNameEpoch, EventNameEpochSetup), 398 EpochCommit: event(ContractNameEpoch, EventNameEpochCommit), 399 VersionBeacon: event(ContractNameNodeVersionBeacon, EventNameVersionBeacon), 400 } 401 402 return events 403 } 404 405 // pre-populate the system contracts and service events for all chains for fast access 406 for _, chain := range flow.AllChainIDs() { 407 serviceEventsForChain[chain] = getServiceEventsForChain(chain) 408 systemContractsForChain[chain] = getSystemContractsForChain(chain) 409 } 410 }