gitlab.com/flarenetwork/coreth@v0.1.1/core/keeper.go (about) 1 // (c) 2021, Flare Networks Limited. All rights reserved. 2 // Please see the file LICENSE for licensing terms. 3 4 package core 5 6 import ( 7 "fmt" 8 "math/big" 9 10 "github.com/ethereum/go-ethereum/common" 11 "github.com/ethereum/go-ethereum/log" 12 13 "gitlab.com/flarenetwork/coreth/core/vm" 14 ) 15 16 // Define errors 17 type ErrInvalidKeeperData struct{} 18 19 func (e *ErrInvalidKeeperData) Error() string { return "invalid return data from keeper trigger" } 20 21 type ErrKeeperDataEmpty struct{} 22 23 func (e *ErrKeeperDataEmpty) Error() string { return "return data from keeper trigger empty" } 24 25 type ErrMaxMintExceeded struct { 26 mintMax *big.Int 27 mintRequest *big.Int 28 } 29 30 func (e *ErrMaxMintExceeded) Error() string { 31 return fmt.Sprintf("mint request of %s exceeded max of %s", e.mintRequest.Text(10), e.mintMax.Text(10)) 32 } 33 34 type ErrMintNegative struct{} 35 36 func (e *ErrMintNegative) Error() string { return "mint request cannot be negative" } 37 38 // Define interface for dependencies 39 type EVMCaller interface { 40 Call(caller vm.ContractRef, addr common.Address, input []byte, gas uint64, value *big.Int) (ret []byte, leftOverGas uint64, err error) 41 GetBlockNumber() *big.Int 42 GetGasLimit() uint64 43 AddBalance(addr common.Address, amount *big.Int) 44 } 45 46 // Define maximums that can change by block height 47 func GetKeeperGasMultiplier(blockNumber *big.Int) uint64 { 48 switch { 49 default: 50 return 100 51 } 52 } 53 54 func GetSystemTriggerContractAddr(blockNumber *big.Int) string { 55 switch { 56 default: 57 return "0x1000000000000000000000000000000000000002" 58 } 59 } 60 61 func GetSystemTriggerSelector(blockNumber *big.Int) []byte { 62 switch { 63 default: 64 return []byte{0x7f, 0xec, 0x8d, 0x38} 65 } 66 } 67 68 func GetPrioritisedFTSOContract(blockTime *big.Int) string { 69 switch { 70 default: 71 return "0x1000000000000000000000000000000000000003" 72 } 73 } 74 75 func GetMaximumMintRequest(blockNumber *big.Int) *big.Int { 76 switch { 77 default: 78 maxRequest, _ := new(big.Int).SetString("50000000000000000000000000", 10) 79 return maxRequest 80 } 81 } 82 83 func triggerKeeper(evm EVMCaller) (*big.Int, error) { 84 bigZero := big.NewInt(0) 85 // Get the contract to call 86 systemTriggerContract := common.HexToAddress(GetSystemTriggerContractAddr(evm.GetBlockNumber())) 87 // Call the method 88 triggerRet, _, triggerErr := evm.Call( 89 vm.AccountRef(systemTriggerContract), 90 systemTriggerContract, 91 GetSystemTriggerSelector(evm.GetBlockNumber()), 92 GetKeeperGasMultiplier(evm.GetBlockNumber())*evm.GetGasLimit(), 93 bigZero) 94 // If no error and a value came back... 95 if triggerErr == nil && triggerRet != nil { 96 // Did we get one big int? 97 if len(triggerRet) == 32 { 98 // Convert to big int 99 // Mint request cannot be less than 0 as SetBytes treats value as unsigned 100 mintRequest := new(big.Int).SetBytes(triggerRet) 101 // return the mint request 102 return mintRequest, nil 103 } else { 104 // Returned length was not 32 bytes 105 return bigZero, &ErrInvalidKeeperData{} 106 } 107 } else { 108 if triggerErr != nil { 109 return bigZero, triggerErr 110 } else { 111 return bigZero, &ErrKeeperDataEmpty{} 112 } 113 } 114 } 115 116 func mint(evm EVMCaller, mintRequest *big.Int) error { 117 // If the mint request is greater than zero and less than max 118 max := GetMaximumMintRequest(evm.GetBlockNumber()) 119 if mintRequest.Cmp(big.NewInt(0)) > 0 && 120 mintRequest.Cmp(max) <= 0 { 121 // Mint the amount asked for on to the keeper contract 122 evm.AddBalance(common.HexToAddress(GetSystemTriggerContractAddr(evm.GetBlockNumber())), mintRequest) 123 } else if mintRequest.Cmp(max) > 0 { 124 // Return error 125 return &ErrMaxMintExceeded{ 126 mintRequest: mintRequest, 127 mintMax: max, 128 } 129 } else if mintRequest.Cmp(big.NewInt(0)) < 0 { 130 // Cannot mint negatives 131 return &ErrMintNegative{} 132 } 133 // No error 134 return nil 135 } 136 137 func triggerKeeperAndMint(evm EVMCaller, log log.Logger) { 138 // Call the keeper 139 mintRequest, triggerErr := triggerKeeper(evm) 140 // If no error... 141 if triggerErr == nil { 142 // time to mint 143 if mintError := mint(evm, mintRequest); mintError != nil { 144 log.Warn("Error minting inflation request", "error", mintError) 145 } 146 } else { 147 log.Warn("Keeper trigger in error", "error", triggerErr) 148 } 149 }