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