def deploy_part_one(admin, confs=1, deployments_json=None): token = ERC20CRV.deploy("Curve DAO Token", "CRV", 18, { "from": admin, "required_confs": confs }) voting_escrow = VotingEscrow.deploy( token, "Vote-escrowed CRV", "veCRV", "veCRV_1.0.0", { "from": admin, "required_confs": confs }, ) deployments = { "ERC20CRV": token.address, "VotingEscrow": voting_escrow.address, } if deployments_json is not None: with open(deployments_json, "w") as fp: json.dump(deployments, fp) print(f"Deployment addresses saved to {deployments_json}") return token, voting_escrow
def development(): """ Vest tokens in a development environment and validate the result. """ token = ERC20CRV.deploy("Curve DAO Token", "CRV", 18, {"from": accounts[0]}) vesting_escrow, vested_amounts = vest_tokens(accounts[0], token, 1) sanity_check(token, vesting_escrow, vested_amounts)
def live_part_two(): admin, _ = config.get_live_admin() with open(config.DEPLOYMENTS_JSON) as fp: deployments = json.load(fp) token = ERC20CRV.at(deployments['ERC20CRV']) voting_escrow = VotingEscrow.at(deployments['VotingEscrow']) deploy_part_two(admin, token, voting_escrow, config.REQUIRED_CONFIRMATIONS, config.DEPLOYMENTS_JSON)
def main(): accounts.from_mnemonic(SEED) admin = accounts[0] token = ERC20CRV.deploy("Curve DAO Token", "CRV", 18, {'from': admin, 'required_confs': confs}) voting_escrow = VotingEscrow.deploy( token, "Vote-escrowed CRV", "veCRV", "veCRV_1.0.0", {'from': admin, 'required_confs': confs} ) coin_a = ERC20.deploy("Coin A", "USDA", 18, {'from': admin, 'required_confs': confs}) coin_b = ERC20.deploy("Coin B", "USDB", 18, {'from': admin, 'required_confs': confs}) coin_a._mint_for_testing(10 ** 9 * 10 ** 18, {'from': admin, 'required_confs': confs}) coin_b._mint_for_testing(10 ** 9 * 10 ** 18, {'from': admin, 'required_confs': confs}) lp_token = ERC20LP.deploy("Some pool", "cPool", 18, 0, {'from': admin, 'required_confs': confs}) pool = CurvePool.deploy([coin_a, coin_b], lp_token, 100, 4 * 10 ** 6, {'from': admin, 'required_confs': confs}) lp_token.set_minter(pool, {'from': admin, 'required_confs': confs}) coin_a.approve(pool, "1000000000000000000000", {'from': admin}) coin_b.approve(pool, "1000000000000000000000", {'from': admin}) pool.add_liquidity(["100000000000000", "200000000000000"], 0, {'from': admin}) contract = CurveRewards.deploy(lp_token, coin_a, {'from': accounts[0], 'required_confs': confs}) contract.setRewardDistribution(accounts[0], {'from': accounts[0], 'required_confs': confs}) registry = Registry.deploy([ZERO_ADDRESS] * 4, {'from': admin, 'required_confs': confs}) coin_a.transfer(contract, 100e18, {'from': accounts[0], 'required_confs': confs}) liquidity_gauge_rewards = LiquidityGaugeReward.deploy(lp_token, '0xbE45e0E4a72aEbF9D08F93E64701964d2CC4cF96', contract, coin_a, {'from': admin, 'required_confs': confs}) for account in DISTRIBUTION_ADDRESSES: coin_a.transfer(account, DISTRIBUTION_AMOUNT, {'from': admin, 'required_confs': confs}) coin_b.transfer(account, DISTRIBUTION_AMOUNT, {'from': admin, 'required_confs': confs}) pool.commit_transfer_ownership(ARAGON_AGENT, {'from': admin, 'required_confs': confs}) pool.apply_transfer_ownership({'from': admin, 'required_confs': confs}) registry.commit_transfer_ownership(ARAGON_AGENT, {'from': admin, 'required_confs': confs}) registry.apply_transfer_ownership({'from': admin, 'required_confs': confs}) gauge_controller = GaugeController.deploy(token, voting_escrow, {'from': admin, 'required_confs': confs}) minter = Minter.deploy(token, gauge_controller, {'from': admin, 'required_confs': confs}) liquidity_gauge = LiquidityGauge.deploy(lp_token, minter, {'from': admin, 'required_confs': confs}) token.set_minter(minter, {'from': admin, 'required_confs': confs}) gauge_controller.add_type(b'Liquidity', {'from': admin, 'required_confs': confs}) gauge_controller.change_type_weight(0, 10 ** 18, {'from': admin, 'required_confs': confs}) gauge_controller.add_gauge(liquidity_gauge, 0, 10 ** 18, {'from': admin, 'required_confs': confs}) gauge_controller.commit_transfer_ownership(ARAGON_AGENT, {'from': admin, 'required_confs': confs}) gauge_controller.apply_transfer_ownership({'from': admin, 'required_confs': confs}) voting_escrow.commit_transfer_ownership(ARAGON_AGENT, {'from': admin, 'required_confs': confs}) voting_escrow.apply_transfer_ownership({'from': admin, 'required_confs': confs}) PoolProxy.deploy({'from': admin, 'required_confs': confs})
def development(): """ Vest tokens in a development environment. * Deploy the DAO token * Run the main deployment and distribution logic * Perform a sanity check to confirm balances and total supply are as expected """ token = ERC20CRV.deploy("Curve DAO Token", "CRV", 18, {'from': accounts[0]}) vesting_escrow, vested_amounts = vest_tokens(accounts[0], accounts[1:5], token, 1) sanity_check(vesting_escrow, vested_amounts)
def transfer_ownership(admin, new_admin, gauge_controller, voting_escrow, pool_proxy, erc20crv, confs=1): gauge_controller = GaugeController.at(gauge_controller) voting_escrow = VotingEscrow.at(voting_escrow) pool_proxy = PoolProxy.at(pool_proxy) erc20crv = ERC20CRV.at(erc20crv) gauge_controller.commit_transfer_ownership(new_admin, { 'from': admin, 'required_confs': confs }) gauge_controller.apply_transfer_ownership({ 'from': admin, 'required_confs': confs }) voting_escrow.commit_transfer_ownership(new_admin, { 'from': admin, 'required_confs': confs }) voting_escrow.apply_transfer_ownership({ 'from': admin, 'required_confs': confs }) pool_proxy.commit_set_admins(new_admin, new_admin, new_admin, { 'from': admin, 'required_confs': confs }) pool_proxy.apply_set_admins({'from': admin, 'required_confs': confs}) erc20crv.set_admin(new_admin, {'from': admin, 'required_confs': confs})
def vest_tokens(admin, funding_admins, token_address, confs): start_idx = len(history) # get token Contract object token = ERC20CRV.at(token_address) # deploy vesting contract start_time = token.future_epoch_time_write.call() vesting_escrow = VestingEscrow.deploy( token, start_time, start_time + VESTING_PERIOD, False, funding_admins, { "from": admin, "required_confs": confs }, ) _log_tx( txid=vesting_escrow.tx.txid, fn_name="VestingEscrow.deploy", contract_address=vesting_escrow.address, ) # load vesting data from json with open(config.LP_VESTING_JSON) as fp: vested_pct = {k.lower(): Decimal(v) for k, v in json.load(fp).items()} for addr in BLACKLIST: if addr.lower() in vested_pct: del vested_pct[addr] # calculate absolute amounts to be distributed initial_total = sum(int(v * TOTAL_AMOUNT) for v in vested_pct.values()) adjustment_pct = Decimal(TOTAL_AMOUNT) / initial_total vested_amounts = sorted( ([k, int(v * TOTAL_AMOUNT * adjustment_pct)] for k, v in vested_pct.items()), key=lambda k: k[1], reverse=True, ) if vested_amounts[-1][1] < 0: raise ValueError( f"'{config.LP_VESTING_JSON}' contains negative amounts!") vested_amounts = [i for i in vested_amounts if i[1]] # floats -> int, we expect to be ever so slightly over, so lets fix that final_total = sum(i[1] for i in vested_amounts) if not 0 < abs(final_total - TOTAL_AMOUNT) < len(vested_amounts): raise ValueError( "Imprecision!!! Distribution amounts are too far off!") for i in range(abs(final_total - TOTAL_AMOUNT)): if final_total < TOTAL_AMOUNT: vested_amounts[i][1] += 1 else: vested_amounts[i][1] -= 1 tx = token.approve(vesting_escrow, TOTAL_AMOUNT, { "from": admin, "required_confs": confs }) _log_tx(txid=tx.txid, fn_name=tx.fn_name, spender=vesting_escrow.address, amount=TOTAL_AMOUNT) tx = vesting_escrow.add_tokens(TOTAL_AMOUNT, { "from": admin, "required_confs": confs }) _log_tx(txid=tx.txid, fn_name=tx.fn_name, amount=TOTAL_AMOUNT) # convert vested_amounts into input args for `VestingEscrow.fund` calls fund_arguments = [([x[0] for x in vested_amounts[i:i + 100]], [x[1] for x in vested_amounts[i:i + 100]]) for i in range(0, len(vested_amounts), 100)] # final call needs to be extended with zero values zeros = 100 - len(fund_arguments[-1][0]) fund_arguments[-1] = ( fund_arguments[-1][0] + ["0x0000000000000000000000000000000000000000"] * zeros, fund_arguments[-1][1] + [0] * zeros, ) # use threading to handle the funding across several accounts funding_threads = [] for acct in [admin] + funding_admins: thread = threading.Thread(target=_fund_accounts, args=(acct, vesting_escrow, fund_arguments, confs)) funding_threads.append(thread) thread.start() for thread in funding_threads: thread.join() # burn all the admin accounts! tx = vesting_escrow.disable_fund_admins({ "from": admin, "required_confs": confs }) _log_tx(txid=tx.txid, fn_name=tx.fn_name) vesting_escrow.commit_transfer_ownership( "0x000000000000000000000000000000000000dead", { "from": admin, "required_confs": confs }) _log_tx(txid=tx.txid, fn_name=tx.fn_name) vesting_escrow.apply_transfer_ownership({ "from": admin, "required_confs": confs }) _log_tx(txid=tx.txid, fn_name=tx.fn_name) gas_used = sum(i.gas_used for i in history[start_idx:]) print(f"Distribution complete! Total gas used: {gas_used}") # return the final vested amounts to be used in `sanity_check`, if desired return vesting_escrow, vested_amounts
def vest_tokens(admin, token_address, confs): token = ERC20CRV.at(token_address) # deploy library and vesting factories target = VestingEscrowSimple.deploy({ "from": admin, "required_confs": confs }) factory_contracts = [] for data in config.FACTORY_ESCROWS: factory = VestingEscrowFactory.deploy(target, data["admin"], { "from": admin, "required_confs": confs }) token.transfer(factory, data["amount"], { "from": admin, "required_confs": confs }) factory_contracts.append((factory, data["amount"])) # deploy standard escrows start_time = token.future_epoch_time_write.call() for data in config.STANDARD_ESCROWS: vesting_escrow = VestingEscrow.deploy( token, start_time, start_time + data["duration"], data["can_disable"], [ZERO_ADDRESS] * 4, { "from": admin, "required_confs": confs }, ) data["contract"] = vesting_escrow total_amount = sum(data["recipients"].values()) token.approve(vesting_escrow, total_amount, { "from": admin, "required_confs": confs }) vesting_escrow.add_tokens(total_amount, { "from": admin, "required_confs": confs }) zeros = 100 - len(data["recipients"]) fund_inputs = tuple(data["recipients"].items()) recipients = [i[0] for i in fund_inputs] + [ZERO_ADDRESS] * zeros amounts = [i[1] for i in fund_inputs] + [0] * zeros vesting_escrow.fund(recipients, amounts, { "from": admin, "required_confs": confs }) if "admin" in data: vesting_escrow.commit_transfer_ownership(data["admin"], { "from": admin, "required_confs": confs }) vesting_escrow.apply_transfer_ownership({ "from": admin, "required_confs": confs }) print("Deployments finished!\n\nFactories:") for factory, amount in factory_contracts: print(f" {factory.address} : {amount} tokens") print("\nStandard Escrows:") for data in config.STANDARD_ESCROWS: total_amount = sum(data["recipients"].values()) print( f" {data['contract'].address}: {len(data['recipients'])} recipients, " f"{total_amount} total tokens, {data['duration']/YEAR} year lock") return config.STANDARD_ESCROWS, factory_contracts