github.com/MetalBlockchain/subnet-evm@v0.4.9/precompile/reward_manager.go (about)

     1  // (c) 2019-2020, Ava Labs, Inc. All rights reserved.
     2  // See the file LICENSE for licensing terms.
     3  
     4  // Code generated
     5  // This file is a generated precompile contract with stubbed abstract functions.
     6  
     7  package precompile
     8  
     9  import (
    10  	"encoding/json"
    11  	"errors"
    12  	"fmt"
    13  	"math/big"
    14  	"strings"
    15  
    16  	"github.com/MetalBlockchain/subnet-evm/accounts/abi"
    17  	"github.com/MetalBlockchain/subnet-evm/constants"
    18  	"github.com/MetalBlockchain/subnet-evm/vmerrs"
    19  
    20  	"github.com/ethereum/go-ethereum/common"
    21  )
    22  
    23  const (
    24  	AllowFeeRecipientsGasCost      uint64 = (writeGasCostPerSlot) + ReadAllowListGasCost // write 1 slot + read allow list
    25  	AreFeeRecipientsAllowedGasCost uint64 = readGasCostPerSlot
    26  	CurrentRewardAddressGasCost    uint64 = readGasCostPerSlot
    27  	DisableRewardsGasCost          uint64 = (writeGasCostPerSlot) + ReadAllowListGasCost // write 1 slot + read allow list
    28  	SetRewardAddressGasCost        uint64 = (writeGasCostPerSlot) + ReadAllowListGasCost // write 1 slot + read allow list
    29  
    30  	// RewardManagerRawABI contains the raw ABI of RewardManager contract.
    31  	RewardManagerRawABI = "[{\"inputs\":[],\"name\":\"allowFeeRecipients\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"areFeeRecipientsAllowed\",\"outputs\":[{\"internalType\":\"bool\",\"name\":\"isAllowed\",\"type\":\"bool\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"currentRewardAddress\",\"outputs\":[{\"internalType\":\"address\",\"name\":\"rewardAddress\",\"type\":\"address\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[],\"name\":\"disableRewards\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"readAllowList\",\"outputs\":[{\"internalType\":\"uint256\",\"name\":\"role\",\"type\":\"uint256\"}],\"stateMutability\":\"view\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setAdmin\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setEnabled\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setNone\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"},{\"inputs\":[{\"internalType\":\"address\",\"name\":\"addr\",\"type\":\"address\"}],\"name\":\"setRewardAddress\",\"outputs\":[],\"stateMutability\":\"nonpayable\",\"type\":\"function\"}]"
    32  )
    33  
    34  // Singleton StatefulPrecompiledContract and signatures.
    35  var (
    36  	_ StatefulPrecompileConfig = &RewardManagerConfig{}
    37  
    38  	ErrCannotAllowFeeRecipients      = errors.New("non-enabled cannot call allowFeeRecipients")
    39  	ErrCannotAreFeeRecipientsAllowed = errors.New("non-enabled cannot call areFeeRecipientsAllowed")
    40  	ErrCannotCurrentRewardAddress    = errors.New("non-enabled cannot call currentRewardAddress")
    41  	ErrCannotDisableRewards          = errors.New("non-enabled cannot call disableRewards")
    42  	ErrCannotSetRewardAddress        = errors.New("non-enabled cannot call setRewardAddress")
    43  
    44  	ErrCannotEnableBothRewards = errors.New("cannot enable both fee recipients and reward address at the same time")
    45  	ErrEmptyRewardAddress      = errors.New("reward address cannot be empty")
    46  
    47  	RewardManagerABI        abi.ABI                     // will be initialized by init function
    48  	RewardManagerPrecompile StatefulPrecompiledContract // will be initialized by init function
    49  
    50  	rewardAddressStorageKey        = common.Hash{'r', 'a', 's', 'k'}
    51  	allowFeeRecipientsAddressValue = common.Hash{'a', 'f', 'r', 'a', 'v'}
    52  )
    53  
    54  type InitialRewardConfig struct {
    55  	AllowFeeRecipients bool           `json:"allowFeeRecipients"`
    56  	RewardAddress      common.Address `json:"rewardAddress,omitempty"`
    57  }
    58  
    59  func (i *InitialRewardConfig) Verify() error {
    60  	switch {
    61  	case i.AllowFeeRecipients && i.RewardAddress != (common.Address{}):
    62  		return ErrCannotEnableBothRewards
    63  	default:
    64  		return nil
    65  	}
    66  }
    67  
    68  func (c *InitialRewardConfig) Equal(other *InitialRewardConfig) bool {
    69  	if other == nil {
    70  		return false
    71  	}
    72  
    73  	return c.AllowFeeRecipients == other.AllowFeeRecipients && c.RewardAddress == other.RewardAddress
    74  }
    75  
    76  func (i *InitialRewardConfig) Configure(state StateDB) {
    77  	// enable allow fee recipients
    78  	if i.AllowFeeRecipients {
    79  		EnableAllowFeeRecipients(state)
    80  	} else if i.RewardAddress == (common.Address{}) {
    81  		// if reward address is empty and allow fee recipients is false
    82  		// then disable rewards
    83  		DisableFeeRewards(state)
    84  	} else {
    85  		// set reward address
    86  		if err := StoreRewardAddress(state, i.RewardAddress); err != nil {
    87  			panic(err)
    88  		}
    89  	}
    90  }
    91  
    92  // RewardManagerConfig implements the StatefulPrecompileConfig
    93  // interface while adding in the RewardManager specific precompile config.
    94  type RewardManagerConfig struct {
    95  	AllowListConfig
    96  	UpgradeableConfig
    97  	InitialRewardConfig *InitialRewardConfig `json:"initialRewardConfig,omitempty"`
    98  }
    99  
   100  func init() {
   101  	parsed, err := abi.JSON(strings.NewReader(RewardManagerRawABI))
   102  	if err != nil {
   103  		panic(err)
   104  	}
   105  	RewardManagerABI = parsed
   106  	RewardManagerPrecompile = createRewardManagerPrecompile(RewardManagerAddress)
   107  }
   108  
   109  // NewRewardManagerConfig returns a config for a network upgrade at [blockTimestamp] that enables
   110  // RewardManager with the given [admins] and [enableds] as members of the allowlist with [initialConfig] as initial rewards config if specified.
   111  func NewRewardManagerConfig(blockTimestamp *big.Int, admins []common.Address, enableds []common.Address, initialConfig *InitialRewardConfig) *RewardManagerConfig {
   112  	return &RewardManagerConfig{
   113  		AllowListConfig: AllowListConfig{
   114  			AllowListAdmins:  admins,
   115  			EnabledAddresses: enableds,
   116  		},
   117  		UpgradeableConfig:   UpgradeableConfig{BlockTimestamp: blockTimestamp},
   118  		InitialRewardConfig: initialConfig,
   119  	}
   120  }
   121  
   122  // NewDisableRewardManagerConfig returns config for a network upgrade at [blockTimestamp]
   123  // that disables RewardManager.
   124  func NewDisableRewardManagerConfig(blockTimestamp *big.Int) *RewardManagerConfig {
   125  	return &RewardManagerConfig{
   126  		UpgradeableConfig: UpgradeableConfig{
   127  			BlockTimestamp: blockTimestamp,
   128  			Disable:        true,
   129  		},
   130  	}
   131  }
   132  
   133  // Equal returns true if [s] is a [*RewardManagerConfig] and it has been configured identical to [c].
   134  func (c *RewardManagerConfig) Equal(s StatefulPrecompileConfig) bool {
   135  	// typecast before comparison
   136  	other, ok := (s).(*RewardManagerConfig)
   137  	if !ok {
   138  		return false
   139  	}
   140  	// modify this boolean accordingly with your custom RewardManagerConfig, to check if [other] and the current [c] are equal
   141  	// if RewardManagerConfig contains only UpgradeableConfig and AllowListConfig you can skip modifying it.
   142  	equals := c.UpgradeableConfig.Equal(&other.UpgradeableConfig) && c.AllowListConfig.Equal(&other.AllowListConfig)
   143  	if !equals {
   144  		return false
   145  	}
   146  
   147  	if c.InitialRewardConfig == nil {
   148  		return other.InitialRewardConfig == nil
   149  	}
   150  
   151  	return c.InitialRewardConfig.Equal(other.InitialRewardConfig)
   152  }
   153  
   154  // Address returns the address of the RewardManager. Addresses reside under the precompile/params.go
   155  // Select a non-conflicting address and set it in the params.go.
   156  func (c *RewardManagerConfig) Address() common.Address {
   157  	return RewardManagerAddress
   158  }
   159  
   160  // Configure configures [state] with the initial configuration.
   161  func (c *RewardManagerConfig) Configure(chainConfig ChainConfig, state StateDB, _ BlockContext) {
   162  	c.AllowListConfig.Configure(state, RewardManagerAddress)
   163  	// configure the RewardManager with the given initial configuration
   164  	if c.InitialRewardConfig != nil {
   165  		c.InitialRewardConfig.Configure(state)
   166  	} else if chainConfig.AllowedFeeRecipients() {
   167  		// configure the RewardManager according to chainConfig
   168  		EnableAllowFeeRecipients(state)
   169  	} else {
   170  		// chainConfig does not have any reward address
   171  		// if chainConfig does not enable fee recipients
   172  		// default to disabling rewards
   173  		DisableFeeRewards(state)
   174  	}
   175  }
   176  
   177  // Contract returns the singleton stateful precompiled contract to be used for RewardManager.
   178  func (c *RewardManagerConfig) Contract() StatefulPrecompiledContract {
   179  	return RewardManagerPrecompile
   180  }
   181  
   182  func (c *RewardManagerConfig) Verify() error {
   183  	if err := c.AllowListConfig.Verify(); err != nil {
   184  		return err
   185  	}
   186  	if c.InitialRewardConfig != nil {
   187  		return c.InitialRewardConfig.Verify()
   188  	}
   189  	return nil
   190  }
   191  
   192  // String returns a string representation of the RewardManagerConfig.
   193  func (c *RewardManagerConfig) String() string {
   194  	bytes, _ := json.Marshal(c)
   195  	return string(bytes)
   196  }
   197  
   198  // GetRewardManagerAllowListStatus returns the role of [address] for the RewardManager list.
   199  func GetRewardManagerAllowListStatus(stateDB StateDB, address common.Address) AllowListRole {
   200  	return getAllowListStatus(stateDB, RewardManagerAddress, address)
   201  }
   202  
   203  // SetRewardManagerAllowListStatus sets the permissions of [address] to [role] for the
   204  // RewardManager list. Assumes [role] has already been verified as valid.
   205  func SetRewardManagerAllowListStatus(stateDB StateDB, address common.Address, role AllowListRole) {
   206  	setAllowListRole(stateDB, RewardManagerAddress, address, role)
   207  }
   208  
   209  // PackAllowFeeRecipients packs the function selector (first 4 func signature bytes).
   210  // This function is mostly used for tests.
   211  func PackAllowFeeRecipients() ([]byte, error) {
   212  	return RewardManagerABI.Pack("allowFeeRecipients")
   213  }
   214  
   215  // EnableAllowFeeRecipients enables fee recipients.
   216  func EnableAllowFeeRecipients(stateDB StateDB) {
   217  	stateDB.SetState(RewardManagerAddress, rewardAddressStorageKey, allowFeeRecipientsAddressValue)
   218  }
   219  
   220  // DisableRewardAddress disables rewards and burns them by sending to Blackhole Address.
   221  func DisableFeeRewards(stateDB StateDB) {
   222  	stateDB.SetState(RewardManagerAddress, rewardAddressStorageKey, constants.BlackholeAddr.Hash())
   223  }
   224  
   225  func allowFeeRecipients(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
   226  	if remainingGas, err = deductGas(suppliedGas, AllowFeeRecipientsGasCost); err != nil {
   227  		return nil, 0, err
   228  	}
   229  	if readOnly {
   230  		return nil, remainingGas, vmerrs.ErrWriteProtection
   231  	}
   232  	// no input provided for this function
   233  
   234  	// Allow list is enabled and AllowFeeRecipients is a state-changer function.
   235  	// This part of the code restricts the function to be called only by enabled/admin addresses in the allow list.
   236  	// You can modify/delete this code if you don't want this function to be restricted by the allow list.
   237  	stateDB := accessibleState.GetStateDB()
   238  	// Verify that the caller is in the allow list and therefore has the right to modify it
   239  	callerStatus := getAllowListStatus(stateDB, RewardManagerAddress, caller)
   240  	if !callerStatus.IsEnabled() {
   241  		return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotAllowFeeRecipients, caller)
   242  	}
   243  	// allow list code ends here.
   244  
   245  	// this function does not return an output, leave this one as is
   246  	EnableAllowFeeRecipients(stateDB)
   247  	packedOutput := []byte{}
   248  
   249  	// Return the packed output and the remaining gas
   250  	return packedOutput, remainingGas, nil
   251  }
   252  
   253  // PackAreFeeRecipientsAllowed packs the include selector (first 4 func signature bytes).
   254  // This function is mostly used for tests.
   255  func PackAreFeeRecipientsAllowed() ([]byte, error) {
   256  	return RewardManagerABI.Pack("areFeeRecipientsAllowed")
   257  }
   258  
   259  // PackAreFeeRecipientsAllowedOutput attempts to pack given isAllowed of type bool
   260  // to conform the ABI outputs.
   261  func PackAreFeeRecipientsAllowedOutput(isAllowed bool) ([]byte, error) {
   262  	return RewardManagerABI.PackOutput("areFeeRecipientsAllowed", isAllowed)
   263  }
   264  
   265  func areFeeRecipientsAllowed(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
   266  	if remainingGas, err = deductGas(suppliedGas, AreFeeRecipientsAllowedGasCost); err != nil {
   267  		return nil, 0, err
   268  	}
   269  	// no input provided for this function
   270  
   271  	stateDB := accessibleState.GetStateDB()
   272  	var output bool
   273  	_, output = GetStoredRewardAddress(stateDB)
   274  
   275  	packedOutput, err := PackAreFeeRecipientsAllowedOutput(output)
   276  	if err != nil {
   277  		return nil, remainingGas, err
   278  	}
   279  
   280  	// Return the packed output and the remaining gas
   281  	return packedOutput, remainingGas, nil
   282  }
   283  
   284  // PackCurrentRewardAddress packs the include selector (first 4 func signature bytes).
   285  // This function is mostly used for tests.
   286  func PackCurrentRewardAddress() ([]byte, error) {
   287  	return RewardManagerABI.Pack("currentRewardAddress")
   288  }
   289  
   290  // PackCurrentRewardAddressOutput attempts to pack given rewardAddress of type common.Address
   291  // to conform the ABI outputs.
   292  func PackCurrentRewardAddressOutput(rewardAddress common.Address) ([]byte, error) {
   293  	return RewardManagerABI.PackOutput("currentRewardAddress", rewardAddress)
   294  }
   295  
   296  // GetStoredRewardAddress returns the current value of the address stored under rewardAddressStorageKey.
   297  // Returns an empty address and true if allow fee recipients is enabled, otherwise returns current reward address and false.
   298  func GetStoredRewardAddress(stateDB StateDB) (common.Address, bool) {
   299  	val := stateDB.GetState(RewardManagerAddress, rewardAddressStorageKey)
   300  	return common.BytesToAddress(val.Bytes()), val == allowFeeRecipientsAddressValue
   301  }
   302  
   303  // StoredRewardAddress stores the given [val] under rewardAddressStorageKey.
   304  func StoreRewardAddress(stateDB StateDB, val common.Address) error {
   305  	// if input is empty, return an error
   306  	if val == (common.Address{}) {
   307  		return ErrEmptyRewardAddress
   308  	}
   309  	stateDB.SetState(RewardManagerAddress, rewardAddressStorageKey, val.Hash())
   310  	return nil
   311  }
   312  
   313  // PackSetRewardAddress packs [addr] of type common.Address into the appropriate arguments for setRewardAddress.
   314  // the packed bytes include selector (first 4 func signature bytes).
   315  // This function is mostly used for tests.
   316  func PackSetRewardAddress(addr common.Address) ([]byte, error) {
   317  	return RewardManagerABI.Pack("setRewardAddress", addr)
   318  }
   319  
   320  // UnpackSetRewardAddressInput attempts to unpack [input] into the common.Address type argument
   321  // assumes that [input] does not include selector (omits first 4 func signature bytes)
   322  func UnpackSetRewardAddressInput(input []byte) (common.Address, error) {
   323  	res, err := RewardManagerABI.UnpackInput("setRewardAddress", input)
   324  	if err != nil {
   325  		return common.Address{}, err
   326  	}
   327  	unpacked := *abi.ConvertType(res[0], new(common.Address)).(*common.Address)
   328  	return unpacked, nil
   329  }
   330  
   331  func setRewardAddress(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
   332  	if remainingGas, err = deductGas(suppliedGas, SetRewardAddressGasCost); err != nil {
   333  		return nil, 0, err
   334  	}
   335  	if readOnly {
   336  		return nil, remainingGas, vmerrs.ErrWriteProtection
   337  	}
   338  	// attempts to unpack [input] into the arguments to the SetRewardAddressInput.
   339  	// Assumes that [input] does not include selector
   340  	// You can use unpacked [inputStruct] variable in your code
   341  	inputStruct, err := UnpackSetRewardAddressInput(input)
   342  	if err != nil {
   343  		return nil, remainingGas, err
   344  	}
   345  
   346  	// Allow list is enabled and SetRewardAddress is a state-changer function.
   347  	// This part of the code restricts the function to be called only by enabled/admin addresses in the allow list.
   348  	// You can modify/delete this code if you don't want this function to be restricted by the allow list.
   349  	stateDB := accessibleState.GetStateDB()
   350  	// Verify that the caller is in the allow list and therefore has the right to modify it
   351  	callerStatus := getAllowListStatus(stateDB, RewardManagerAddress, caller)
   352  	if !callerStatus.IsEnabled() {
   353  		return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotSetRewardAddress, caller)
   354  	}
   355  	// allow list code ends here.
   356  
   357  	if err := StoreRewardAddress(stateDB, inputStruct); err != nil {
   358  		return nil, remainingGas, err
   359  	}
   360  	// this function does not return an output, leave this one as is
   361  	packedOutput := []byte{}
   362  
   363  	// Return the packed output and the remaining gas
   364  	return packedOutput, remainingGas, nil
   365  }
   366  
   367  func currentRewardAddress(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
   368  	if remainingGas, err = deductGas(suppliedGas, CurrentRewardAddressGasCost); err != nil {
   369  		return nil, 0, err
   370  	}
   371  
   372  	// no input provided for this function
   373  	stateDB := accessibleState.GetStateDB()
   374  	output, _ := GetStoredRewardAddress(stateDB)
   375  	packedOutput, err := PackCurrentRewardAddressOutput(output)
   376  	if err != nil {
   377  		return nil, remainingGas, err
   378  	}
   379  
   380  	// Return the packed output and the remaining gas
   381  	return packedOutput, remainingGas, nil
   382  }
   383  
   384  // PackDisableRewards packs the include selector (first 4 func signature bytes).
   385  // This function is mostly used for tests.
   386  func PackDisableRewards() ([]byte, error) {
   387  	return RewardManagerABI.Pack("disableRewards")
   388  }
   389  
   390  func disableRewards(accessibleState PrecompileAccessibleState, caller common.Address, addr common.Address, input []byte, suppliedGas uint64, readOnly bool) (ret []byte, remainingGas uint64, err error) {
   391  	if remainingGas, err = deductGas(suppliedGas, DisableRewardsGasCost); err != nil {
   392  		return nil, 0, err
   393  	}
   394  	if readOnly {
   395  		return nil, remainingGas, vmerrs.ErrWriteProtection
   396  	}
   397  	// no input provided for this function
   398  
   399  	// Allow list is enabled and DisableRewards is a state-changer function.
   400  	// This part of the code restricts the function to be called only by enabled/admin addresses in the allow list.
   401  	// You can modify/delete this code if you don't want this function to be restricted by the allow list.
   402  	stateDB := accessibleState.GetStateDB()
   403  	// Verify that the caller is in the allow list and therefore has the right to modify it
   404  	callerStatus := getAllowListStatus(stateDB, RewardManagerAddress, caller)
   405  	if !callerStatus.IsEnabled() {
   406  		return nil, remainingGas, fmt.Errorf("%w: %s", ErrCannotDisableRewards, caller)
   407  	}
   408  	// allow list code ends here.
   409  	DisableFeeRewards(stateDB)
   410  	// this function does not return an output, leave this one as is
   411  	packedOutput := []byte{}
   412  
   413  	// Return the packed output and the remaining gas
   414  	return packedOutput, remainingGas, nil
   415  }
   416  
   417  // createRewardManagerPrecompile returns a StatefulPrecompiledContract with getters and setters for the precompile.
   418  // Access to the getters/setters is controlled by an allow list for [precompileAddr].
   419  func createRewardManagerPrecompile(precompileAddr common.Address) StatefulPrecompiledContract {
   420  	var functions []*statefulPrecompileFunction
   421  	functions = append(functions, createAllowListFunctions(precompileAddr)...)
   422  
   423  	methodAllowFeeRecipients, ok := RewardManagerABI.Methods["allowFeeRecipients"]
   424  	if !ok {
   425  		panic("given method does not exist in the ABI")
   426  	}
   427  	functions = append(functions, newStatefulPrecompileFunction(methodAllowFeeRecipients.ID, allowFeeRecipients))
   428  
   429  	methodAreFeeRecipientsAllowed, ok := RewardManagerABI.Methods["areFeeRecipientsAllowed"]
   430  	if !ok {
   431  		panic("given method does not exist in the ABI")
   432  	}
   433  	functions = append(functions, newStatefulPrecompileFunction(methodAreFeeRecipientsAllowed.ID, areFeeRecipientsAllowed))
   434  
   435  	methodCurrentRewardAddress, ok := RewardManagerABI.Methods["currentRewardAddress"]
   436  	if !ok {
   437  		panic("given method does not exist in the ABI")
   438  	}
   439  	functions = append(functions, newStatefulPrecompileFunction(methodCurrentRewardAddress.ID, currentRewardAddress))
   440  
   441  	methodDisableRewards, ok := RewardManagerABI.Methods["disableRewards"]
   442  	if !ok {
   443  		panic("given method does not exist in the ABI")
   444  	}
   445  	functions = append(functions, newStatefulPrecompileFunction(methodDisableRewards.ID, disableRewards))
   446  
   447  	methodSetRewardAddress, ok := RewardManagerABI.Methods["setRewardAddress"]
   448  	if !ok {
   449  		panic("given method does not exist in the ABI")
   450  	}
   451  	functions = append(functions, newStatefulPrecompileFunction(methodSetRewardAddress.ID, setRewardAddress))
   452  
   453  	// Construct the contract with no fallback function.
   454  	contract := newStatefulPrecompileWithFunctionSelectors(nil, functions)
   455  	return contract
   456  }