Exemplo n.º 1
0
 def __repr__(self):
     return "Schedule(sett={},token={},initalTokensLocked={},startTime={},duration={} days,endTime={}".format(
         self.sett,
         self.token,
         self.initialTokensLocked,
         to_utc_date(self.startTime),
         to_days(self.duration),
         to_utc_date(self.endTime),
     )
    def printState(self, title):
        console.print(
            "\n[yellow]=== 🦡 Rewards Schedule: {} 🦡 ===[/yellow]".format(
                title))
        table = []

        rewardsEscrow = self.badger.rewardsEscrow
        for key, amount in self.amounts.items():
            geyser = self.badger.getGeyser(key)
            assert rewardsEscrow.isApproved(geyser)
            """
            function signalTokenLock(
                address geyser,
                address token,
                uint256 amount,
                uint256 durationSec,
                uint256 startTime
            )
            """

            encoded = rewardsEscrow.signalTokenLock.encode_input(
                geyser, self.badger.token, amount, self.duration, self.start)

            table.append([
                key,
                geyser,
                self.badger.token,
                val(amount),
                to_utc_date(self.start),
                to_utc_date(self.end),
                to_days(self.duration),
                val(self.tokensPerDay(amount)),
                self.badger.rewardsEscrow,
                encoded,
            ])

        print(
            tabulate(
                table,
                headers=[
                    "key",
                    "geyser",
                    "token",
                    "total amount",
                    "start time",
                    "end time",
                    "duration",
                    "rate per day",
                    "destination",
                    "encoded call",
                ],
                tablefmt="rst",
            ))

        print("total distributed: ", val(self.total))
Exemplo n.º 3
0
    def print_logger_unlock_schedules(self, beneficiary, name=None):
        logger = self.rewardsLogger

        schedules = logger.getAllUnlockSchedulesFor(beneficiary)

        if not name:
            name = ""

        console.print(f"[cyan]=== Latest Unlock Schedules {name}===[/cyan]")
        table = []

        if len(schedules) == 0:
            return
        for schedule in schedules:
            print(schedule)
            s = LoggerUnlockSchedule(schedule)

            digg_shares = s.token == self.digg.token

        if digg_shares:
            scaled = shares_to_fragments(s.amount)
        else:
            scaled = val(amount=s.amount, token=s.token)

        table.append([
            name,
            s.beneficiary,
            s.token,
            scaled,
            to_days(s.duration),
            to_utc_date(s.start),
            to_utc_date(s.end),
            "{:.0f}".format(s.start),
            "{:.0f}".format(s.end),
        ])

        print(
            tabulate(
                table,
                headers=[
                    "name",
                    "beneficiary",
                    "token",
                    "amount",
                    "duration",
                    "start",
                    "end",
                    "start",
                    "end",
                ],
            ))
        print("\n")
Exemplo n.º 4
0
    def print_latest_unlock_schedules(self, geyser, name=None):
        if not name:
            name = ""

        console.print(f"[cyan]=== Latest Unlock Schedules {name}===[/cyan]")
        table = []
        tokens = geyser.getDistributionTokens()

        for token in tokens:
            schedules = geyser.getUnlockSchedulesFor(token)
            num_schedules = geyser.unlockScheduleCount(token)

            if num_schedules == 0:
                continue
            last_schedule = num_schedules - 1
            s = UnlockSchedule(token, schedules[last_schedule])

            digg_shares = token == self.digg.token

            if digg_shares:
                scaled = shares_to_fragments(s.amount)
            else:
                scaled = val(amount=s.amount, token=token)

            table.append([
                name,
                token,
                scaled,
                to_days(s.duration),
                to_utc_date(s.start),
                to_utc_date(s.end),
                "{:.0f}".format(s.start),
                "{:.0f}".format(s.end),
            ])

        print(
            tabulate(
                table,
                headers=[
                    "geyser",
                    "token",
                    "amount",
                    "duration",
                    "start",
                    "end",
                    "start",
                    "end",
                ],
            ))
        print("\n")
Exemplo n.º 5
0
def get_distributed_for_token_at(token, endTime, schedules, name):
    totalToDistribute = 0
    for index, schedule in enumerate(schedules):
        if endTime < schedule.startTime:
            toDistribute = 0
            console.log("\nSchedule {} for {} completed\n".format(index, name))
        else:
            rangeDuration = endTime - schedule.startTime
            toDistribute = min(
                schedule.initialTokensLocked,
                int(schedule.initialTokensLocked * rangeDuration // schedule.duration),
            )
            if schedule.startTime <= endTime and schedule.endTime >= endTime:
                console.log(
                    "Tokens distributed by schedule {} at {} are {}% of total\n".format(
                        index,
                        to_utc_date(schedule.startTime),
                        (int(toDistribute) / int(schedule.initialTokensLocked) * 100),
                    )
                )

                console.log(
                    "Total duration of schedule elapsed is {} hours out of {} hours, or {}% of total duration.\n".format(
                        to_hours(rangeDuration),
                        to_hours(schedule.duration),
                        rangeDuration / schedule.duration * 100,
                    )
                )
        totalToDistribute += toDistribute
    return totalToDistribute
Exemplo n.º 6
0
def main():
    badger = connect_badger(badger_config.prod_json)

    table = []

    tree = badger.badgerTree
    lastPublish = tree.lastPublishTimestamp()
    timeSinceLastPublish = chain.time() - lastPublish

    table.append(["now", to_utc_date(chain.time())])
    table.append(["---------------", "--------------------"])
    table.append(["lastPublishTimestamp", lastPublish])
    table.append(["lastPublishDate", to_utc_date(lastPublish)])
    table.append(["---------------", "--------------------"])
    table.append(["secondsSinceLastPublish", timeSinceLastPublish])
    table.append(["hoursSinceLastPublish", timeSinceLastPublish / 3600])

    print(tabulate(table, headers=["metric", "value"]))
    def get_distributed_for_token_at(self, token, endTime, read=False):
        """
        Get total distribution for token within range, across unlock schedules
        """
        totalToDistribute = 0

        unlockSchedules = self.unlockSchedules[token]
        index = 0
        for schedule in unlockSchedules:

            if endTime < schedule.startTime:
                toDistribute = 0
                rangeDuration = endTime - schedule.startTime
                if read:
                    console.print(
                        "\n[cyan]Schedule {} for {}: Complete[/cyan]".format(
                            index, self.key))
            else:
                rangeDuration = endTime - schedule.startTime
                toDistribute = min(
                    schedule.initialTokensLocked,
                    int(schedule.initialTokensLocked * rangeDuration //
                        schedule.duration),
                )

                # Output if in rewards range, or read flag is on
                if read and (schedule.startTime <= endTime
                             and schedule.endTime >= endTime):
                    console.print(
                        "\n[blue] == Schedule {} for {} == [/blue]".format(
                            index, self.key))

                    console.log(
                        "Total tokens distributed by schedule starting at {} by the end of rewards cycle are {} out of {} total."
                        .format(
                            to_utc_date(schedule.startTime),
                            val(toDistribute),
                            val(schedule.initialTokensLocked),
                        ))
                    console.log(
                        "Total duration of schedule elapsed is {} hours out of {} hours, or {}% of total duration."
                        .format(to_hours(rangeDuration),
                                to_hours(schedule.duration),
                                rangeDuration / schedule.duration * 100))

                    console.log("\n")

            totalToDistribute += toDistribute
            index += 1
        return totalToDistribute
Exemplo n.º 8
0
def printUniTrade(method, params):
    path = params[2]
    input_token = path[0]
    output_token = path[-1]

    table = []
    table.append(["input token", input_token])
    table.append(["output token", output_token])
    table.append(["expected output", params[0]])
    table.append(["max input", params[1]])
    table.append(["path", params[2]])
    table.append(["recipient", params[3]])
    table.append(["expiration time", to_utc_date(params[4])])
    table.append(["time until expiration", days(params[4] - chain.time())])
    console.print(tabulate(table, headers=["metric", "value"]))
Exemplo n.º 9
0
def main():
    badger = connect_badger("deploy-final.json")
    bBadger = badger.getSett("native.badger")

    escrows = [
        "0x1fc3C85456322C8514c0ff7694Ea4Ef5bC7F9f37",
        "0xaeDb773C226e6d74f2cd3542372076779Ff6fA6E"
    ]

    timelocks = [
        "0x2Bc1A5E26ad0316375E68942fe0B387adE6b9254",
        "0x7C651D13DfB87748b0F05914dFb40E5B15a78D35",
        "0xB6c9e9Ba41291044Cf5dadFB22D72d3fe9312880",
        "0xdbd185c59f64d2d39c6ababf5d701669417a002d"
        # "0x1fc3C85456322C8514c0ff7694Ea4Ef5bC7F9f37",
        # "0xaeDb773C226e6d74f2cd3542372076779Ff6fA6E"
    ]

    for address in timelocks:
        vesting = interface.ITokenTimelock(address)

        console.print(
            {
                "token": vesting.token(),
                "beneficiary": vesting.beneficiary(),
                "releaseTime": vesting.releaseTime(),
                "releaseDate": to_utc_date(vesting.releaseTime()),
            }
        )

    chain.sleep(days(182))
    chain.mine()

    for address in timelocks:
        vesting = interface.ITokenTimelock(address)
        beneficiary = accounts.at(vesting.beneficiary(), force=True)
        pre = get_token_balances([bBadger], [vesting, beneficiary])
        vesting.release({"from": badger.deployer})
        post = get_token_balances([bBadger], [vesting, beneficiary])
        diff_token_balances(pre, post)
Exemplo n.º 10
0
def main():
    badger = connect_badger("deploy-final.json")

    test_user = accounts.at(decouple.config("TEST_ACCOUNT"), force=True)

    distribute_test_ether(test_user, Wei("20 ether"))
    distribute_from_whales(test_user, assets=["bBadger", "badger", "usdc"])

    rest = get_active_rewards_schedule(badger)
    usdc = interface.IERC20(registry.tokens.usdc)

    usdc_per_badger = 40.37 * 0.75
    usdc_total = 13386240

    multi = GnosisSafe(badger.devMultisig)

    badger_total_scaled = usdc_total / usdc_per_badger

    badger_total = Wei(str(badger_total_scaled) + " ether")

    bBadger = badger.getSett("native.badger")

    ppfs = bBadger.getPricePerFullShare()

    bBadger_total = int(badger_total / ppfs * 10**18)

    badger_total = Wei(str(badger_total_scaled) + " ether")

    console.print({
        "TRADE": "BASED",
        "usdc_per_badger": usdc_per_badger,
        "usdc_total": usdc_total,
        "badger_total_scaled": badger_total_scaled,
        "badger_total": badger_total,
        "ppfs": ppfs,
        "bBadger_total": str(bBadger_total),
    })

    params = {
        "beneficiary": "0x3159b46a7829a0dbfa856888af768fe7146e7418",
        "duration": days(182),
        "usdcAmount": usdc_total * 10**6,
        "bBadgerAmount": bBadger_total,
        # "usdcAmount": 0,
        # "bBadgerAmount": 0,
    }

    console.print(params)

    # # Oxb1 Test
    beneficiary = accounts.at(params["beneficiary"], force=True)

    escrow = OtcEscrow.at("0x7163fB2fA38Ea3BBc1F8525F3d8D0417C0c9d903")

    # bBadger.transfer(badger.devMultisig, Wei("100000 ether"), {"from": test_user})

    pre = get_token_balances(
        [usdc, bBadger], [test_user, escrow, badger.devMultisig, beneficiary])
    pre.print()

    # assert usdc.balanceOf(params["beneficiary"]) >= params["usdcAmount"]

    # multi.execute(MultisigTxMetadata(description="Transfer to 0xb1"), {
    #     "to": bBadger.address,
    #     "data": bBadger.transfer.encode_input(escrow, bBadger_total + Wei("1000 ether"))
    # })

    # assert usdc.allowance(beneficiary, escrow) >= params["usdcAmount"]

    # usdc.approve(escrow, params["usdcAmount"], {"from": beneficiary})
    # tx = escrow.swap({"from": beneficiary})

    tx = multi.execute(MultisigTxMetadata(description="Swap"), {
        "to": escrow.address,
        "data": escrow.swap.encode_input()
    },
                       print_output=False)

    chain.mine()

    print(tx.call_trace())

    vesting = interface.ITokenTimelock(
        tx.events["VestingDeployed"][0]["vesting"])

    console.print({
        "token": vesting.token(),
        "beneficiary": vesting.beneficiary(),
        "releaseTime": to_utc_date(vesting.releaseTime()),
    })

    post = get_token_balances(
        [usdc, bBadger], [test_user, escrow, badger.devMultisig, beneficiary])

    diff_token_balances(pre, post)
    try:
        vesting.release({"from": test_user})
    except:
        print("early vest failed!")

    chain.sleep(days(182))
    chain.mine()
    # End

    vesting.release({"from": test_user})

    post = get_token_balances(
        [usdc, bBadger], [test_user, escrow, badger.devMultisig, beneficiary])

    diff_token_balances(pre, post)

    return

    escrow = OtcEscrow.deploy(
        params["beneficiary"],
        params["duration"],
        params["usdcAmount"],
        params["bBadgerAmount"],
        {"from": badger.deployer},
    )

    beneficiary = accounts.at(params["beneficiary"], force=True)
    usdc.transfer(beneficiary, params["usdcAmount"], {"from": test_user})
    usdc.transfer(beneficiary, 1500000000000, {"from": test_user})

    badger.token.transfer(badger.devMultisig, badger_total,
                          {"from": test_user})

    multi.execute(
        MultisigTxMetadata(description="Whitelist Multi"),
        {
            "to": bBadger.address,
            "data": bBadger.approveContractAccess.encode_input(
                badger.devMultisig),
        },
    )

    assert badger.token.balanceOf(badger.devMultisig) > Wei("100 ether")

    multi.execute(
        MultisigTxMetadata(description="Approve bBadger Contract"),
        {
            "to": badger.token.address,
            "data": badger.token.approve.encode_input(bBadger, badger_total),
        },
    )

    multi.execute(
        MultisigTxMetadata(description="Deposit"),
        {
            "to": bBadger.address,
            "data": bBadger.deposit.encode_input(badger_total)
        },
    )

    console.print(
        "bBadger.balanceOf(badger.devMultisig)",
        bBadger.balanceOf(badger.devMultisig), params["bBadgerAmount"],
        params["bBadgerAmount"] - bBadger.balanceOf(badger.devMultisig))
    assert bBadger.balanceOf(badger.devMultisig) >= params["bBadgerAmount"]

    chain.mine()
    chain.sleep(14)
    chain.mine()

    multi.execute(
        MultisigTxMetadata(description="Transfer"),
        {
            "to": bBadger.address,
            "data": bBadger.transfer.encode_input(escrow,
                                                  params["bBadgerAmount"]),
        },
    )

    assert bBadger.balanceOf(escrow) == params["bBadgerAmount"]

    multi.execute(
        MultisigTxMetadata(description="Revoke"),
        {
            "to": escrow.address,
            "data": escrow.revoke.encode_input()
        },
    )

    assert bBadger.balanceOf(escrow) == 0
    assert bBadger.balanceOf(badger.devMultisig) >= params["bBadgerAmount"]

    print(bBadger.balanceOf(badger.devMultisig))

    bBadger.transfer(escrow, params["bBadgerAmount"], {"from": test_user})

    pre = get_token_balances(
        [usdc, bBadger], [test_user, escrow, badger.devMultisig, beneficiary])
    console.print(pre)

    assert usdc.balanceOf(beneficiary) >= params["usdcAmount"]
    assert bBadger.balanceOf(escrow) == params["bBadgerAmount"]

    usdc.approve(escrow, params["usdcAmount"], {"from": beneficiary})
    tx = escrow.swap({"from": beneficiary})

    post = get_token_balances(
        [usdc, bBadger], [test_user, escrow, badger.devMultisig, beneficiary])

    console.print(tx.events)
    post.print()
    diff_token_balances(pre, post)

    vesting = interface.ITokenTimelock(
        tx.events["VestingDeployed"][0]["vesting"])

    console.print({
        "token": vesting.token(),
        "beneficiary": vesting.beneficiary(),
        "releaseTime": to_utc_date(vesting.releaseTime()),
    })

    chain.sleep(days(365))
    chain.mine()

    vesting.release({"from": test_user})
Exemplo n.º 11
0
    def printState(self, title):
        console.print(
            "\n[yellow]=== 🦡 Rewards Schedule: {} 🦡 ===[/yellow]".format(
                title))
        table = []

        rewardsEscrow = self.badger.rewardsEscrow
        for key, dist in self.distributions.items():
            if key == "native.digg":
                continue
            print(key, dist)
            geyser = self.badger.getGeyser(key)
            print(geyser)
            assert rewardsEscrow.isApproved(geyser)
            for asset, value in dist.toGeyser.items():
                """
                function signalTokenLock(
                    address geyser,
                    address token,
                    uint256 amount,
                    uint256 durationSec,
                    uint256 startTime
                )
                """

                encoded = rewardsEscrow.signalTokenLock.encode_input(
                    geyser, asset_to_address(asset), value, self.duration,
                    self.start)

                asset_contract = interface.IERC20(asset_to_address(asset))

                scaled = val(value, decimals=18)
                if asset == "digg":
                    scaled = val(shares_to_fragments(value), decimals=9)

                table.append([
                    key,
                    # geyser,
                    asset,
                    value,
                    scaled,
                    to_utc_date(self.start),
                    to_utc_date(self.end),
                    to_days(self.duration),
                    # geyser.address,
                    # encoded,
                ])

        print(
            tabulate(
                table,
                headers=[
                    "key",
                    # "geyser",
                    "token",
                    "total amount",
                    "scaled amount",
                    "start time",
                    "end time",
                    "duration",
                    # "rate per day",
                    # "destination",
                    # "encoded call",
                ],
                tablefmt="rst",
            ))
        print("total distributed for {}: ".format(asset),
              val(self.totals[asset]))
    def testTransactions(self):
        rewardsEscrow = self.badger.rewardsEscrow
        multi = GnosisSafe(self.badger.devMultisig)

        # Setup
        accounts[7].transfer(multi.get_first_owner(), Wei("2 ether"))
        print(
            "Supplied ETH",
            accounts.at(multi.get_first_owner(), force=True).balance(),
        )

        badger = self.badger
        tree = self.badger.badgerTree

        before = badger.token.balanceOf(tree)
        top_up = Wei("200000 ether")

        # Top up Tree
        # TODO: Make the amount based on what we'll require for the next week
        id = multi.addTx(
            MultisigTxMetadata(
                description="Top up badger tree",
                operation="Top Up Badger Tree",
            ),
            {
                "to":
                rewardsEscrow.address,
                "data":
                rewardsEscrow.transfer.encode_input(badger.token, tree,
                                                    top_up),
            },
        )

        tx = multi.executeTx(id)

        after = badger.token.balanceOf(tree)
        assert after == before + top_up

        for key, distribution in self.distributions.items():
            console.print("===== Distributions for {} =====".format(key),
                          style="bold yellow")

            # == Distribute to Geyser ==
            geyser = self.badger.getGeyser(key)

            # Approve Geyser as recipient if required
            if not rewardsEscrow.isApproved(geyser):
                id = multi.addTx(
                    MultisigTxMetadata(
                        description="Approve StakingRewards " + key,
                        operation="transfer",
                    ),
                    {
                        "to":
                        rewardsEscrow.address,
                        "data":
                        rewardsEscrow.approveRecipient.encode_input(geyser),
                    },
                )

                multi.executeTx(id)

            numSchedules = geyser.unlockScheduleCount(self.badger.token)
            console.print(
                "Geyser Distribution for {}: {}".format(
                    key, val(distribution.toGeyser)),
                style="yellow",
            )

            id = multi.addTx(
                MultisigTxMetadata(
                    description="Signal unlock schedule for " + key,
                    operation="signalTokenLock",
                ),
                {
                    "to":
                    rewardsEscrow.address,
                    "data":
                    rewardsEscrow.signalTokenLock.encode_input(
                        geyser,
                        self.badger.token,
                        distribution.toGeyser,
                        self.duration,
                        self.start,
                    ),
                },
            )

            multi.executeTx(id)

            # Verify Results
            numSchedulesAfter = geyser.unlockScheduleCount(self.badger.token)

            console.print(
                "Schedule Addition",
                {
                    "numSchedules": numSchedules,
                    "numSchedulesAfter": numSchedulesAfter
                },
            )

            assert numSchedulesAfter == numSchedules + 1

            unlockSchedules = geyser.getUnlockSchedulesFor(self.badger.token)
            schedule = unlockSchedules[-1]
            print(schedule)
            assert schedule[0] == distribution.toGeyser
            assert schedule[1] == self.end
            assert schedule[2] == self.duration
            assert schedule[3] == self.start

            # == Distribute to StakingRewards, if relevant ==
            if distribution.toStakingRewards > 0:
                stakingRewards = self.badger.getSettRewards(key)
                console.print(
                    "Staking Rewards Distribution for {}: {}".format(
                        key, val(distribution.toStakingRewards)),
                    style="yellow",
                )

                # Approve if not approved
                if not rewardsEscrow.isApproved(stakingRewards):
                    id = multi.addTx(
                        MultisigTxMetadata(
                            description="Approve StakingRewards " + key,
                            operation="transfer",
                        ),
                        {
                            "to":
                            rewardsEscrow.address,
                            "data":
                            rewardsEscrow.approveRecipient.encode_input(
                                stakingRewards),
                        },
                    )

                    multi.executeTx(id)

                    assert rewardsEscrow.isApproved(stakingRewards) == True

                # Add tokens if insufficent tokens
                preBal = self.badger.token.balanceOf(stakingRewards)
                if preBal < distribution.toStakingRewards:
                    required = distribution.toStakingRewards - preBal
                    console.print(
                        "� We need to add {} to the {} Badger supply of {} to reach the goal of {} Badger"
                        .format(
                            val(required),
                            key,
                            val(preBal),
                            val(distribution.toStakingRewards),
                        ),
                        style="blue",
                    )

                    id = multi.addTx(
                        MultisigTxMetadata(
                            description="Top up tokens for staking rewards " +
                            key,
                            operation="transfer",
                        ),
                        {
                            "to":
                            rewardsEscrow.address,
                            "data":
                            rewardsEscrow.transfer.encode_input(
                                self.badger.token, stakingRewards, required),
                        },
                    )

                    multi.executeTx(id)

                assert (self.badger.token.balanceOf(stakingRewards) >=
                        distribution.toStakingRewards)

                # Modify the rewards duration, if necessary
                if stakingRewards.rewardsDuration() != self.duration:
                    id = multi.addTx(
                        MultisigTxMetadata(
                            description="Modify Staking Rewards duration for "
                            + key,
                            operation="call.notifyRewardAmount",
                        ),
                        {
                            "to":
                            stakingRewards.address,
                            "data":
                            stakingRewards.setRewardsDuration.encode_input(
                                self.duration),
                        },
                    )
                    tx = multi.executeTx(id)

                # assert stakingRewards.rewardsDuration() == self.duration

                # Notify Rewards Amount
                id = multi.addTx(
                    MultisigTxMetadata(
                        description="Distribute Staking Rewards For " + key,
                        operation="call.notifyRewardAmount",
                    ),
                    {
                        "to":
                        stakingRewards.address,
                        "data":
                        stakingRewards.notifyRewardAmount.encode_input(
                            self.start,
                            distribution.toStakingRewards,
                        ),
                    },
                )

                tx = multi.executeTx(id)
                console.print(tx.call_trace())
                console.print("notify rewards events", tx.events)

                # Verify Results

                rewardsDuration = stakingRewards.rewardsDuration()
                rewardRate = stakingRewards.rewardRate()
                periodFinish = stakingRewards.periodFinish()
                lastUpdate = stakingRewards.lastUpdateTime()

                oldRewardsRate = Wei("50000 ether") // rewardsDuration

                console.log({
                    "start":
                    to_utc_date(self.start),
                    "end":
                    to_utc_date(self.end),
                    "finish":
                    to_utc_date(periodFinish),
                    "rewardRate":
                    rewardRate,
                    "expectedRewardRate":
                    distribution.toStakingRewards // rewardsDuration,
                    "rewardsRateDiff":
                    rewardRate -
                    distribution.toStakingRewards // rewardsDuration,
                    "oldRewardsRate":
                    oldRewardsRate,
                    "howTheRateChanged":
                    (distribution.toStakingRewards // rewardsDuration) /
                    oldRewardsRate,
                    "howWeExpectedItToChange":
                    Wei("35000 ether") / Wei("50000 ether"),
                    "lastUpdate":
                    to_utc_date(lastUpdate),
                })

                assert lastUpdate == self.start
                assert rewardsDuration == self.duration
                assert rewardRate == distribution.toStakingRewards // rewardsDuration
                assert periodFinish == self.start + self.duration

                bal = self.badger.token.balanceOf(stakingRewards)
                assert bal >= distribution.toStakingRewards

                if bal > distribution.toStakingRewards * 2:
                    console.print(
                        "[red] Warning: Staking rewards for {} has excessive coins [/red]"
                        .format(key))

                # Harvest the rewards and ensure the amount updated is appropriate
                strategy = self.badger.getStrategy(key)
                keeper = accounts.at(strategy.keeper(), force=True)

                before = strategy.balance()
                chain.sleep(self.start - chain.time() + 2)
                strategy.harvest({"from": keeper})
                after = strategy.balance()

                print({"before": before, "after": after})
    def __init__(self,
                 badger,
                 multi,
                 key,
                 distributions,
                 start=0,
                 duration=0,
                 end=0):
        # == Distribute to Geyser ==
        geyser = badger.getGeyser(key)
        rewardsEscrow = badger.rewardsEscrow

        self.start = start
        self.duration = duration
        self.end = end

        multi = GnosisSafe(badger.devMultisig)
        for asset, dist in distributions.items():
            token = asset_to_address(asset)
            self.validate_staking_rewards_emission(key, asset)

            stakingRewards = badger.getSettRewards(key)
            console.print(
                "Staking Rewards Distribution for asset {} on {}: {}".format(
                    asset, key, val(dist)),
                style="yellow",
            )

            # Approve if not approved
            if not rewardsEscrow.isApproved(stakingRewards):
                id = multi.addTx(
                    MultisigTxMetadata(
                        description="Approve StakingRewards " + key,
                        operation="transfer",
                    ),
                    {
                        "to":
                        rewardsEscrow.address,
                        "data":
                        rewardsEscrow.approveRecipient.encode_input(
                            stakingRewards),
                    },
                )

                multi.executeTx(id)

                assert rewardsEscrow.isApproved(stakingRewards) == True

            # Add tokens if insufficent tokens
            preBal = badger.token.balanceOf(stakingRewards)
            print("PreBalance", val(preBal))

            if preBal < dist:
                required = dist - preBal
                console.print(
                    "⊁ We need to add {} to the {} Badger supply of {} to reach the goal of {} Badger"
                    .format(
                        val(required),
                        key,
                        val(preBal),
                        val(dist),
                    ),
                    style="blue",
                )

                id = multi.addTx(
                    MultisigTxMetadata(
                        description="Top up tokens for staking rewards " + key,
                        operation="transfer",
                    ),
                    {
                        "to":
                        rewardsEscrow.address,
                        "data":
                        rewardsEscrow.transfer.encode_input(
                            badger.token, stakingRewards, required),
                    },
                )

                multi.executeTx(id)

            assert badger.token.balanceOf(stakingRewards) >= dist

            # Modify the rewards duration, if necessary
            if stakingRewards.rewardsDuration() != self.duration:
                id = multi.addTx(
                    MultisigTxMetadata(
                        description="Modify Staking Rewards duration for " +
                        key,
                        operation="call.notifyRewardAmount",
                    ),
                    {
                        "to":
                        stakingRewards.address,
                        "data":
                        stakingRewards.setRewardsDuration.encode_input(
                            self.duration),
                    },
                )
                tx = multi.executeTx(id)

            # assert stakingRewards.rewardsDuration() == self.duration

            # Notify Rewards Amount
            id = multi.addTx(
                MultisigTxMetadata(
                    description="Distribute Staking Rewards For " + key,
                    operation="call.notifyRewardAmount",
                ),
                {
                    "to":
                    stakingRewards.address,
                    "data":
                    stakingRewards.notifyRewardAmount.encode_input(
                        self.start,
                        dist,
                    ),
                },
            )

            tx = multi.executeTx(id)
            console.print(tx.call_trace())
            console.print("notify rewards events", tx.events)

            # Verify Results

            rewardsDuration = stakingRewards.rewardsDuration()
            rewardRate = stakingRewards.rewardRate()
            periodFinish = stakingRewards.periodFinish()
            lastUpdate = stakingRewards.lastUpdateTime()

            oldRewardsRate = Wei("50000 ether") // rewardsDuration

            console.log({
                "start":
                to_utc_date(self.start),
                "end":
                to_utc_date(self.end),
                "finish":
                to_utc_date(periodFinish),
                "rewardRate":
                rewardRate,
                "expectedRewardRate":
                dist // rewardsDuration,
                "rewardsRateDiff":
                rewardRate - dist // rewardsDuration,
                "oldRewardsRate":
                oldRewardsRate,
                "howTheRateChanged":
                (dist // rewardsDuration) / oldRewardsRate,
                "howWeExpectedItToChange":
                Wei("35000 ether") / Wei("50000 ether"),
                "lastUpdate":
                to_utc_date(lastUpdate),
            })

            assert lastUpdate == self.start
            assert rewardsDuration == self.duration
            assert rewardRate == dist // rewardsDuration
            assert periodFinish == self.start + self.duration

            bal = badger.token.balanceOf(stakingRewards)
            assert bal >= dist

            if bal > dist * 2:
                console.print(
                    "[red] Warning: Staking rewards for {} has excessive coins [/red]"
                    .format(key))

            # Harvest the rewards and ensure the amount updated is appropriate
            strategy = badger.getStrategy(key)
            keeper = accounts.at(strategy.keeper(), force=True)

            before = strategy.balance()
            chain.sleep(self.start - chain.time() + 2)
            strategy.harvest({"from": keeper})
            after = strategy.balance()

            print({"before": before, "after": after})