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 }