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  }