def check_eta(self):
        """ Cast spells that meet their schedule.

        First, the local database is updated with spells that have been scheduled between the last block
        reviewed and the most recent block receieved. Next, it simply traverses through each spell address,
        checking if its schedule has been reached/passed. If it has, it attempts to `cast` the spell.
        """
        blockNumber = self.web3.eth.blockNumber
        now = self.web3.eth.getBlock(blockNumber).timestamp
        self.logger.info(f'Checking scheduled spells on block {blockNumber}')

        self.database.update_db_etas(blockNumber)
        etas = self.database.db.get(doc_id=3)["upcoming_etas"]

        yays = list(etas.keys())

        for yay in yays:
            if etas[yay] <= now:
                spell = DSSSpell(self.web3, Address(yay))

                if spell.done() == False:
                    receipt = spell.cast().transact(gas_price=self.gas_price())

                    if receipt.successful == True:
                        del etas[yay]

                else:
                    del etas[yay]

        self.database.db.update({'upcoming_etas': etas}, doc_ids=[3])
    def check_schedule(self, spell: DSSSpell, yay: str):
        """ Schedules spells that haven't been scheduled nor casted """
        if is_contract_at(self.web3, Address(yay)):

            # Functional with DSSSpells but not DSSpells (not compatiable with DSPause)
            if spell.done() == False and self.database.get_eta_inUnix(
                    spell) == 0:
                self.logger.info(f'Scheduling spell ({yay})')
                spell.schedule().transact(gas_price=self.gas_price())
Example #3
0
    def check_hat(self):
        """ Ensures the Hat is on the proposal (spell, EOA, multisig, etc) with the most approval.

        First, the local database is updated with proposal addresses (yays) that have been `etched` in DSChief between
        the last block reviewed and the most recent block receieved. Next, it simply traverses through each address,
        checking if its approval has surpased the current Hat. If it has, it will `lift` the hat.

        If the current or new hat hasn't been casted nor plotted in the pause, it will `schedule` the spell
        """
        blockNumber = self.web3.eth.blockNumber
        self.logger.info(f'Checking Hat on block {blockNumber}')

        self.database.update_db_yays(blockNumber)
        yays = self.database.db.get(doc_id=2)["yays"]

        hat = self.dss.ds_chief.get_hat().address
        hatApprovals = self.dss.ds_chief.get_approvals(hat)

        contender, highestApprovals = hat, hatApprovals

        for yay in yays:
            contenderApprovals = self.dss.ds_chief.get_approvals(yay)
            if contenderApprovals > highestApprovals:
                contender = yay
                highestApprovals = contenderApprovals

        if contender != hat:
            self.logger.info(f'Lifting hat')
            self.logger.info(f'Old hat ({hat}) with Approvals {hatApprovals}')
            self.logger.info(
                f'New hat ({contender}) with Approvals {highestApprovals}')
            self.dss.ds_chief.lift(
                Address(contender)).transact(gas_price=self.gas_price)
        else:
            self.logger.info(
                f'Current hat ({hat}) with Approvals {hatApprovals}')

        # Read the hat; either is equivalent to the contender or old hat
        hatNew = self.dss.ds_chief.get_hat().address
        if hatNew != hat:
            self.logger.info(f'Confirmed ({contender}) now has the hat')

        spell = DSSSpell(self.web3, Address(hatNew)) if is_contract_at(
            self.web3, Address(hatNew)) else None

        # Schedules spells that haven't been scheduled nor casted
        if spell is not None:
            # Functional with DSSSpells but not DSSpells (not compatiable with DSPause)
            if spell.done() == False and self.database.get_eta_inUnix(
                    spell) == 0:
                self.logger.info(f'Scheduling spell ({yay})')
                spell.schedule().transact(gas_price=self.gas_price)
        else:
            self.logger.warning(
                f'Spell is an EOA or 0x0, so keeper will not attempt to call schedule()'
            )
Example #4
0
    def get_etas(self, yays, blockNumber: int):
        """ Get all upcoming etas """
        etas = {}
        for yay in yays:

            #Check if yay is an address to an EOA or a contract
            if is_contract_at(self.web3, Address(yay)):
                spell = DSSSpell(self.web3, Address(yay))
                eta = self.get_eta_inUnix(spell)

                if (eta > 0) and (spell.done() == False):
                    etas[spell.address.address] = eta

        return etas