Skip to content

Commit

Permalink
Merge pull request lidofinance#16 from lidofinance/feature/referral_p…
Browse files Browse the repository at this point in the history
…artners_factories

Feat: add tooling scripts to charge ET with regular referral partners payouts
  • Loading branch information
TheDZhon authored Mar 23, 2022
2 parents 93a75bd + ab4a8e3 commit e5e6a09
Show file tree
Hide file tree
Showing 13 changed files with 877 additions and 22 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,12 @@ Easy Track motion is a lightweight voting considered to have passed if the minim

## Use cases for Easy Track motions

There are three types of votings run periodically by the Lido DAO that are proposed to be wrapped into the new Easy Track motions.
There are four types of votings run periodically by the Lido DAO that are proposed to be wrapped into the new Easy Track motions.

- Node Operators increasing staking limits
- Funds being allocated into reward programs
- Funds being allocated to LEGO program
- Funds being allocated to the whitelisted referral partners

See [specification.md](https://github.com/lidofinance/easy-track/blob/master/specification.md) for full specification.

Expand Down
158 changes: 158 additions & 0 deletions scripts/deploy_reward_programs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
from brownie import chain, network

from utils.config import (
get_env,
get_is_live,
get_deployer_account,
prompt_bool,
network_name
)
from utils import (
deployment,
lido,
deployed_easy_track,
log
)

from brownie import (
RewardProgramsRegistry,
AddRewardProgram,
RemoveRewardProgram,
TopUpRewardPrograms
)

def main():
netname = "goerli" if network_name().split('-')[0] == "goerli" else "mainnet"

contracts = lido.contracts(network=netname)
et_contracts = deployed_easy_track.contracts(network=netname)
deployer = get_deployer_account(get_is_live(), network=netname)

easy_track = et_contracts.easy_track
evm_script_executor = et_contracts.evm_script_executor

# address allowed to create motions to add, remove or top up reward programs
reward_programs_multisig = get_env("REWARD_PROGRAMS_MULTISIG")

log.br()

log.nb("Current network", network.show_active(), color_hl=log.color_magenta)
log.nb("Using deployed addresses for", netname, color_hl=log.color_yellow)
log.ok("chain id", chain.id)
log.ok("Deployer", deployer)
log.ok("Governance Token", contracts.ldo)
log.ok("Aragon Voting", contracts.aragon.voting)
log.ok("Aragon Finance", contracts.aragon.finance)

log.br()

log.nb("Reward Programs Multisig", reward_programs_multisig)
log.nb("Deployed EasyTrack", easy_track)
log.nb("Deployed EVMScript Executor", evm_script_executor)

log.br()

print("Proceed? [yes/no]: ")

if not prompt_bool():
log.nb("Aborting")
return

tx_params = { "from": deployer }
if (get_is_live()):
tx_params["priority_fee"] = "2 gwei"
tx_params["max_fee"] = "300 gwei"

(
reward_programs_registry,
add_reward_program,
remove_reward_program,
top_up_reward_programs
) = deploy_reward_programs_contracts(
evm_script_executor=evm_script_executor,
lido_contracts=contracts,
reward_programs_multisig=reward_programs_multisig,
tx_params=tx_params,
)

log.br()

log.ok("Reward programs factories have been deployed...")
log.nb("Deployed RewardProgramsRegistry", reward_programs_registry)
log.nb("Deployed AddRewardProgram", add_reward_program)
log.nb("Deployed RemoveRewardProgram", remove_reward_program)
log.nb("Deployed TopUpRewardPrograms", top_up_reward_programs)

log.br()

if (get_is_live() and get_env("FORCE_VERIFY", False)):
log.ok("Trying to verify contracts...")
RewardProgramsRegistry.publish_source(reward_programs_registry)
AddRewardProgram.publish_source(add_reward_program)
RemoveRewardProgram.publish_source(remove_reward_program)
TopUpRewardPrograms.publish_source(top_up_reward_programs)

log.br()

if easy_track.hasRole(easy_track.DEFAULT_ADMIN_ROLE(), deployer):
log.ok("Easy Track is under deployer control")
log.ok("Finalize deploy by adding factories to Easy Track?")

if not prompt_bool():
log.nb("Aborting")
return

deployment.add_evm_script_reward_programs_factories(
easy_track=easy_track,
add_reward_program=add_reward_program,
remove_reward_program=remove_reward_program,
top_up_reward_programs=top_up_reward_programs,
reward_programs_registry=reward_programs_registry,
lido_contracts=contracts
)
elif easy_track.hasRole(easy_track.DEFAULT_ADMIN_ROLE(), contracts.aragon.voting):
log.ok("Easy Track is under DAO Voting control")
log.ok("To finalize deploy, please create voting that adds factories to Easy Track")
else:
log.ok("Easy Track is under another account's control")
log.ok("To finalize deploy, please manually add factories to Easy Track")

print("Hit <Enter> to quit script")
input()


def deploy_reward_programs_contracts(
evm_script_executor,
lido_contracts,
reward_programs_multisig,
tx_params,
):
reward_programs_registry = deployment.deploy_reward_programs_registry(
voting=lido_contracts.aragon.voting,
evm_script_executor=evm_script_executor,
tx_params=tx_params,
)
add_reward_program = deployment.deploy_add_reward_program(
reward_programs_registry=reward_programs_registry,
reward_programs_multisig=reward_programs_multisig,
tx_params=tx_params,
)
remove_reward_program = deployment.deploy_remove_reward_program(
reward_programs_registry=reward_programs_registry,
reward_programs_multisig=reward_programs_multisig,
tx_params=tx_params,
)
top_up_reward_programs = deployment.deploy_top_up_reward_programs(
finance=lido_contracts.aragon.finance,
governance_token=lido_contracts.ldo,
reward_programs_registry=reward_programs_registry,
reward_programs_multisig=reward_programs_multisig,
tx_params=tx_params,
)

return (
reward_programs_registry,
add_reward_program,
remove_reward_program,
top_up_reward_programs
)
118 changes: 118 additions & 0 deletions scripts/vote_for_reward_programs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
from typing import Optional

from brownie import chain, network

from utils.vote_for_new_factories import (
FactoryToAdd,
FactoryToRemove,
create_voting_on_new_factories
)

from utils.config import (
get_env,
get_is_live,
get_deployer_account,
network_name
)

from utils import (
lido,
deployed_easy_track,
log
)

def create_permission(contract, method):
return contract.address + getattr(contract, method).signature[2:]

def start_vote(
netname: str,
deployer: Optional[str]
) -> int:
contracts = lido.contracts(network=netname)
et_contracts = deployed_easy_track.contracts(network=netname)

tx_params = { "from": deployer }
if (get_is_live()):
tx_params["priority_fee"] = "2 gwei"
tx_params["max_fee"] = "300 gwei"

easy_track = et_contracts.easy_track

prog_type = get_env("REWARD_PROGRAMS_TYPE")
reward_programs = None
if prog_type == "reward_programs":
reward_programs = et_contracts.reward_programs
elif prog_type == "referral_partners":
reward_programs = et_contracts.referral_partners
else:
raise Exception(f"Unknown REWARD_PROGRAMS_TYPE: {prog_type}")

log.br()

log.nb("Current network", network.show_active(), color_hl=log.color_magenta)
log.nb("Using deployed addresses for", netname, color_hl=log.color_yellow)
log.ok("chain id", chain.id)
log.ok("Deployer", deployer)
log.ok("Reward programs type", prog_type)
log.ok("Aragon Voting", contracts.aragon.voting)
log.ok("Aragon Finance", contracts.aragon.finance)

log.br()

log.nb("Deployed EasyTrack", easy_track)
log.nb("Deployed RewardProgramsRegistry", reward_programs.reward_programs_registry)
log.nb("Deployed AddRewardProgram", reward_programs.add_reward_program)
log.nb("Deployed RemoveRewardProgram", reward_programs.remove_reward_program)
log.nb("Deployed TopUpRewardPrograms", reward_programs.top_up_reward_programs)

log.br()

factories_to_remove = [
# Intentionally left empty
# Use if need to replace some factories
# FactoryToRemove(factory=...)
]

factories_to_add = [
FactoryToAdd(
factory=reward_programs.add_reward_program,
permissions=create_permission(
reward_programs.reward_programs_registry,
"addRewardProgram"
)
),
FactoryToAdd(
factory=reward_programs.top_up_reward_programs,
permissions=create_permission(
contracts.aragon.finance,
"newImmediatePayment")
),
FactoryToAdd(
factory=reward_programs.remove_reward_program,
permissions=create_permission(
reward_programs.reward_programs_registry,
"removeRewardProgram"
)
)
]

vote_id = create_voting_on_new_factories(
easy_track=easy_track,
factories_to_remove=factories_to_remove,
factories_to_add=factories_to_add,
network=netname,
tx_params=tx_params
)

return vote_id

def main():
netname = "goerli" if network_name().split('-')[0] == "goerli" else "mainnet"
deployer = get_deployer_account(get_is_live(), network=netname)

vote_id = start_vote(netname, deployer)

vote_id >= 0 and print(f'Vote successfully started! Vote id: {vote_id}.')

print("Hit <Enter> to quit script")
input()
2 changes: 0 additions & 2 deletions specification.md
Original file line number Diff line number Diff line change
Expand Up @@ -438,8 +438,6 @@ Creates EVMScript to remove reward program from `RewardProgramsRegistry`. `_evmS

Decodes `_evmScriptCallData` into tuple `(address _rewardProgram)`.

# Additional Contracts

## RewardProgramsRegistry

Stores list of addresses with reward programs. Inherits from OpenZeppelin's `AccessControl` contract. TopUpRewardsProgram EVMScript factory allows transfers only to addresses listed in RewardProgramsRegistry.
Expand Down
46 changes: 43 additions & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import os
from typing import Optional

import pytest
import brownie
from brownie import chain

import constants
from utils.lido import contracts
Expand Down Expand Up @@ -147,12 +151,10 @@ def increase_node_operator_staking_limit(
def add_reward_program(owner, reward_programs_registry, AddRewardProgram):
return owner.deploy(AddRewardProgram, owner, reward_programs_registry)


@pytest.fixture(scope="module")
def remove_reward_program(owner, reward_programs_registry, RemoveRewardProgram):
return owner.deploy(RemoveRewardProgram, owner, reward_programs_registry)


@pytest.fixture(scope="module")
def top_up_reward_programs(
owner, finance, ldo, reward_programs_registry, TopUpRewardPrograms
Expand All @@ -161,7 +163,6 @@ def top_up_reward_programs(
TopUpRewardPrograms, owner, reward_programs_registry, finance, ldo
)


@pytest.fixture(scope="module")
def top_up_lego_program(owner, finance, lego_program, TopUpLegoProgram):
return owner.deploy(TopUpLegoProgram, owner, finance, lego_program)
Expand Down Expand Up @@ -283,3 +284,42 @@ def method(account, amount):
ldo.transfer(account, amount, {"from": agent})

return method

class Helpers:
@staticmethod
def execute_vote(accounts, vote_id, dao_voting, ldo_vote_executors_for_tests, topup='0.1 ether'):
if dao_voting.getVote(vote_id)[0]:
for holder_addr in ldo_vote_executors_for_tests:
print('voting from acct:', holder_addr)
accounts[0].transfer(holder_addr, topup)
account = accounts.at(holder_addr, force=True)
dao_voting.vote(vote_id, True, False, {'from': account})

# wait for the vote to end
chain.sleep(3 * 60 * 60 * 24)
chain.mine()

assert dao_voting.canExecute(vote_id)
tx = dao_voting.executeVote(vote_id, {'from': accounts[0]})

print(f'vote #{vote_id} executed')
return tx


@pytest.fixture(scope='module')
def helpers():
return Helpers


@pytest.fixture(scope='module')
def vote_id_from_env() -> Optional[int]:
_env_name = "OMNIBUS_VOTE_ID"
if os.getenv(_env_name):
try:
vote_id = int(os.getenv(_env_name))
print(f'OMNIBUS_VOTE_ID env var is set, using existing vote #{vote_id}')
return vote_id
except:
pass

return None
Loading

0 comments on commit e5e6a09

Please sign in to comment.