Skip to content

Commit

Permalink
Merge pull request #46 from cbergz/master
Browse files Browse the repository at this point in the history
DIP 24
  • Loading branch information
dgogel authored Aug 17, 2023
2 parents 8569735 + 500d7c2 commit 6ba80f4
Show file tree
Hide file tree
Showing 12 changed files with 270 additions and 7 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"eslint-plugin-no-only-tests": "^2.6.0",
"eth-sig-util": "^3.0.1",
"ethereum-waffle": "^3.4.0",
"hardhat": "^2.8.0",
"hardhat": "^2.17.0",
"lodash": "^4.17.21",
"luxon": "^2.0.2",
"reflect-metadata": "^0.1.13",
Expand Down
4 changes: 3 additions & 1 deletion src/config/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
const configSchema = {
DEPLOYMENT_LOGS: parseBoolean({ default: null }),
FORK_MAINNET: parseBoolean({ default: false }),
FORK_BLOCK_NUMBER: parseInteger({ default: 17474647 }),
FORK_BLOCK_NUMBER: parseInteger({ default: 17526224 }),
HARDHAT_SIMULATE_AFFECTED_STAKERS: parseInteger({ default: 3 }),
OVERRIDE_DEPLOYER_ADDRESS: parseString({ default: null }),
PROMPT_AUTO_YES: parseBoolean({ default: false }),
Expand Down Expand Up @@ -37,6 +37,8 @@ const configSchema = {
TEST_V3_DATA_AVAILABILITY_WITH_PROPOSAL: parseBoolean({ default: true }),
FUND_OPS_TRUST_v2_PROPOSAL_ID: parseInteger({ default: null }),
TEST_FUND_OPS_TRUST_v2_WITH_PROPOSAL: parseBoolean({ default: true }),
UPDATE_MERKLE_DISTRIBUTOR_REWARDS_PARAMETERS_DIP24_PROPOSAL_ID: parseInteger( { default: null }),
TEST_UPDATE_MERKLE_DISTRIBUTOR_REWARDS_PARAMETERS_DIP24_WITH_PROPOSAL: parseBoolean({ default: true }),
};

const config = parseSchema(configSchema);
Expand Down
9 changes: 9 additions & 0 deletions src/deploy-config/base-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,15 @@ const config = {
// Price derived is $1.53 using Binance.com DYDX/USDT on
// Using market price of $1.53, rounded amount to be transferred is 4,314,000 DYDX
DOT_FUNDING_AMOUNT_v2: '4314000000000000000000000',

// Update Merkle Distributor LP Rewards (DIP 24)
// Proposal to reduce the current LP rewards by 50%. Trading rewards will not be changed.
// Alpha parameter will remain unchanged.
// LP rewards being reduced by 50% from '1,150,685' to '575,343' per epoch.
UPDATE_MERKLE_DISTRIBUTOR_LP_REWARDS_AMOUNT_DIP24: '575343000000000000000000',
// Trading rewards and alpha are unchanged.
UPDATE_MERKLE_DISTRIBUTOR_TRADER_REWARDS_AMOUNT_DIP24: '1582192000000000000000000',
UPDATE_MERKLE_DISTRIBUTOR_ALPHA_PARAMETER_DIP24: '0',
};

export type BaseConfig = typeof config;
Expand Down
4 changes: 4 additions & 0 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,3 +57,7 @@ export const DIP_22_IPFS_HASH = '0x11e2866e87f43c68118021b1efaf1053be1f3cb0d25c0
// DIP_23_IPFS_HASH taken from the link below:
// https://github.com/dydxfoundation/dip/blob/master/content/ipfs-dips/DIP-23-Ipfs-hashes.json
export const DIP_23_IPFS_HASH = '0x5aca381042cb641c1000126d5a183c38b17492eb60a86910973d0c3f1e867f43';

// DIP_24_IPFS_HASH taken from the link below:
// https://github.com/dydxfoundation/dip/blob/master/content/ipfs-dips/DIP-24-Ipfs-hashes.json
export const DIP_24_IPFS_HASH = '0x3a7575988e0aa9c066830c1e8f8958d9b81d0365cfb6e478076ae111d3f3190c';
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { SignerWithAddress } from '@nomiclabs/hardhat-ethers/signers';

import {
DydxGovernor__factory,
} from '../../types';
import { getDeployConfig } from '../deploy-config';
import { getDeployerSigner } from '../deploy-config/get-deployer-address';
import { getHre } from '../hre';
import { log } from '../lib/logging';
import { waitForTx } from '../lib/util';
import { Proposal } from '../types';

export async function updateMerkleDistributorRewardsParametersDIP24Proposal({
proposalIpfsHashHex,
governorAddress,
merkleDistributorAddress,
shortTimelockAddress,
signer,
}: {
proposalIpfsHashHex: string,
governorAddress: string,
merkleDistributorAddress: string,
shortTimelockAddress: string,
signer?: SignerWithAddress,
}) {
const hre = getHre();
const deployConfig = getDeployConfig();
const deployer = signer || await getDeployerSigner();
const deployerAddress = deployer.address;
log(`Creating Update Merkle Distributor Rewards Parameters DIP 24 proposal with proposer ${deployerAddress}.\n`);

const governor = await new DydxGovernor__factory(deployer).attach(governorAddress);
const proposalId = await governor.getProposalsCount();
const proposal: Proposal = [
shortTimelockAddress,
[merkleDistributorAddress],
['0'],
['setRewardsParameters(uint256,uint256,uint256)'],
[hre.ethers.utils.defaultAbiCoder.encode(
['uint256', 'uint256', 'uint256'],
[
deployConfig.UPDATE_MERKLE_DISTRIBUTOR_LP_REWARDS_AMOUNT_DIP24,
deployConfig.UPDATE_MERKLE_DISTRIBUTOR_TRADER_REWARDS_AMOUNT_DIP24,
deployConfig.UPDATE_MERKLE_DISTRIBUTOR_ALPHA_PARAMETER_DIP24,
],
)],
[false],
proposalIpfsHashHex,
];

await waitForTx(await governor.create(...proposal));

return {
proposalId,
};
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { types } from 'hardhat/config';

import mainnetAddresses from '../../src/deployed-addresses/mainnet.json';
import { hardhatTask } from '../../src/hre';
import { DIP_24_IPFS_HASH } from '../../src/lib/constants';
import { updateMerkleDistributorRewardsParametersDIP24Proposal } from '../../src/migrations/update-merkle-distributor-rewards-parameters-dip24';

hardhatTask('deploy:update-merkle-distributor-rewards-parameters-dip24-proposal', 'Create DIP24 proposal to update merkle distributor rewards parameters')
.addParam('proposalIpfsHashHex', 'IPFS hash for the uploaded DIP describing the proposal', DIP_24_IPFS_HASH, types.string)
.addParam('governorAddress', 'Address of the deployed DydxGovernor contract', mainnetAddresses.governor, types.string)
.addParam('shortTimelockAddress', 'Address of the deployed short timelock Executor contract', mainnetAddresses.shortTimelock, types.string)
.addParam('merkleDistributorAddress', 'Address of the deployed merkle distributor contract', mainnetAddresses.merkleDistributor, types.string)
.setAction(async (args) => {
await updateMerkleDistributorRewardsParametersDIP24Proposal(args);
});

4 changes: 3 additions & 1 deletion test/helpers/get-deployed-contracts-for-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
executeUpdateMerkleDistributorRewardsParametersV2ProposalForTest,
executeV3DataAvailabilityProposalForTest,
executeOpsTrustV2ProposalForTest,
executeUpdateMerkleDistributorRewardsParametersDIP24ProposalForTest,
} from '../migrations/deploy-contracts-for-test';

let globalDeployedContracts: AllDeployedContracts;
Expand Down Expand Up @@ -67,9 +68,10 @@ async function getDeployedContractsForTest(): Promise<AllDeployedContracts> {
await executeOpsTrustProposalForTest(deployedContracts);
await executeUpdateMerkleDistributorRewardsParametersV2ProposalForTest(deployedContracts);
await executeV3DataAvailabilityProposalForTest(deployedContracts);
await executeOpsTrustV2ProposalForTest(deployedContracts);
}
// Execute the proposals which have not yet been executed on mainnet.
await executeOpsTrustV2ProposalForTest(deployedContracts);
await executeUpdateMerkleDistributorRewardsParametersDIP24ProposalForTest(deployedContracts);
await configureForTest(deployedContracts);
return deployedContracts;
}
19 changes: 19 additions & 0 deletions test/migrations/deploy-contracts-for-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { fundOpsTrustV2ViaProposal, fundOpsTrustV2NoProposal } from './ops-trust
import { fundSafetyModuleRecoveryNoProposal, fundSafetyModuleRecoveryViaProposal } from './safety-module-compensation';
import { executeSafetyModuleUpgradeNoProposal, executeSafetyModuleUpgradeViaProposal } from './safety-module-fix';
import { executeStarkProxyUpgradeNoProposal, executeStarkProxyUpgradeViaProposal } from './stark-proxy-fix';
import { updateMerkleDistributorRewardsParametersDIP24NoProposal, updateMerkleDistributorRewardsParametersDIP24ViaProposal } from './update-merkle-distributor-rewards-parameters-dip24';
import { updateMerkleDistributorRewardsParametersViaProposal, updateMerkleDistributorRewardsParametersNoProposal } from './update-merkle-distributor-rewards-parameters-proposal';
import { updateMerkleDistributorRewardsParametersV2ViaProposal, updateMerkleDistributorRewardsParametersV2NoProposal } from './update-merkle-distributor-rewards-parameters-v2-proposal';
import { executeV3DataAvailabilityViaProposal, executeV3DataAvailabilityNoProposal } from './v3-data-availability-proposal';
Expand Down Expand Up @@ -353,6 +354,24 @@ export async function executeOpsTrustV2ProposalForTest(
}
}

export async function executeUpdateMerkleDistributorRewardsParametersDIP24ProposalForTest(
deployedContracts: AllDeployedContracts,
) {
if (config.TEST_UPDATE_MERKLE_DISTRIBUTOR_REWARDS_PARAMETERS_DIP24_WITH_PROPOSAL) {
await updateMerkleDistributorRewardsParametersDIP24ViaProposal({
dydxTokenAddress: deployedContracts.dydxToken.address,
governorAddress: deployedContracts.governor.address,
merkleDistributorAddress: deployedContracts.merkleDistributor.address,
shortTimelockAddress: deployedContracts.shortTimelock.address,
});
} else {
await updateMerkleDistributorRewardsParametersDIP24NoProposal({
merkleDistributorAddress: deployedContracts.merkleDistributor.address,
shortTimelockAddress: deployedContracts.shortTimelock.address,
});
}
}

/**
* After the deploy scripts have run, this function configures the contracts for testing.
*/
Expand Down
118 changes: 118 additions & 0 deletions test/migrations/update-merkle-distributor-rewards-parameters-dip24.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import BNJS from 'bignumber.js';
import { BigNumberish } from 'ethers';

import config from '../../src/config';
import { getDeployConfig } from '../../src/deploy-config';
import { getDeployerSigner } from '../../src/deploy-config/get-deployer-address';
import { DIP_24_IPFS_HASH } from '../../src/lib/constants';
import { log } from '../../src/lib/logging';
import { waitForTx } from '../../src/lib/util';
import { impersonateAndFundAccount } from '../../src/migrations/helpers/impersonate-account';
import { updateMerkleDistributorRewardsParametersDIP24Proposal } from '../../src/migrations/update-merkle-distributor-rewards-parameters-dip24';
import { DydxGovernor__factory, DydxToken__factory, MerkleDistributorV1__factory } from '../../types';
import { advanceBlock, increaseTimeAndMine } from '../helpers/evm';

export async function updateMerkleDistributorRewardsParametersDIP24NoProposal({
merkleDistributorAddress,
shortTimelockAddress,
}: {
merkleDistributorAddress: string,
shortTimelockAddress: string,
}) {
const deployConfig = getDeployConfig();
const shortTimelockSigner = await impersonateAndFundAccount(shortTimelockAddress);
const merkleDistributor = new MerkleDistributorV1__factory(shortTimelockSigner).attach(merkleDistributorAddress);

await merkleDistributor.setRewardsParameters(
deployConfig.UPDATE_MERKLE_DISTRIBUTOR_LP_REWARDS_AMOUNT_DIP24,
deployConfig.UPDATE_MERKLE_DISTRIBUTOR_TRADER_REWARDS_AMOUNT_DIP24,
deployConfig.UPDATE_MERKLE_DISTRIBUTOR_ALPHA_PARAMETER_DIP24,
);
}

export async function updateMerkleDistributorRewardsParametersDIP24ViaProposal({
dydxTokenAddress,
governorAddress,
merkleDistributorAddress,
shortTimelockAddress,
}: {
dydxTokenAddress: string,
governorAddress: string,
merkleDistributorAddress: string,
shortTimelockAddress: string,
}) {
const deployConfig = getDeployConfig();
const deployer = await getDeployerSigner();
const dydxToken = new DydxToken__factory(deployer).attach(dydxTokenAddress);
const governor = new DydxGovernor__factory(deployer).attach(governorAddress);

// Pick a voter with enough tokens to meet the quorum requirement.
const voterAddress = deployConfig.TOKEN_ALLOCATIONS.DYDX_TRADING.ADDRESS;
const voter = await impersonateAndFundAccount(voterAddress);
const voterBalance = await dydxToken.balanceOf(voterAddress);

if (voterBalance.lt(new BNJS('2e25').toFixed())) {
throw new Error('Not enough votes to pass the proposal.');
}

// Vote on an existing proposal (can be used with mainnet forking).
let proposalId: BigNumberish;

if (config.UPDATE_MERKLE_DISTRIBUTOR_REWARDS_PARAMETERS_DIP24_PROPOSAL_ID !== null) {
proposalId = config.UPDATE_MERKLE_DISTRIBUTOR_REWARDS_PARAMETERS_DIP24_PROPOSAL_ID;
} else {
log('Creating proposal');
({ proposalId } = await updateMerkleDistributorRewardsParametersDIP24Proposal({
proposalIpfsHashHex: DIP_24_IPFS_HASH,
governorAddress,
merkleDistributorAddress,
shortTimelockAddress,
signer: voter,
}));

log('Waiting for voting to begin');
for (let i = 0; i < deployConfig.VOTING_DELAY_BLOCKS + 1; i++) {
if (i > 0 && i % 2000 === 0) {
log('mining', i);
}
await advanceBlock();
}
}

let proposalState = await governor.getProposalState(proposalId);
if (proposalState !== 2) {
throw new Error('Expected proposal to be in the voting phase.');
}

log('Submitting vote');
await waitForTx(await governor.connect(voter).submitVote(proposalId, true));

log('Waiting for voting to end');
let minedCount = 0;
for (; ;) {
for (let i = 0; i < 2000; i++) {
await advanceBlock();
minedCount++;
}
log('mining', minedCount);
proposalState = await governor.getProposalState(proposalId);
if (proposalState !== 2) {
break;
}
}

if (proposalState !== 4) {
throw new Error(`Expected proposal to have succeeded but state was ${proposalState}`);
}

log('Queueing the proposal');
await waitForTx(await governor.queue(proposalId));
const delaySeconds = deployConfig.SHORT_TIMELOCK_CONFIG.DELAY;
await increaseTimeAndMine(delaySeconds);

log('Executing the proposal');
await waitForTx(await governor.execute(proposalId));
log('Proposal executed');

log('\n=== UPDATE MERKLE DISTRIBUTOR REWARDS PARAMETERS DIP24 COMPLETE ===\n');
}
4 changes: 2 additions & 2 deletions test/misc/ops-trust-v2-proposal.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { expect } from 'chai';

import { DIP_23_IPFS_HASH } from '../../src/lib/constants';
import { describeContract, TestContext } from '../helpers/describe-contract';
import { describeContractHardhatRevertBefore, TestContext } from '../helpers/describe-contract';

function init() {}

describeContract('ops-trust-v2-proposal', init, (ctx: TestContext) => {
describeContractHardhatRevertBefore('ops-trust-v2-proposal', init, (ctx: TestContext) => {

it('Proposal IPFS hash is correct', async () => {
const opsTrustV2ProposalId = 13;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { expect } from 'chai';
import { BigNumber } from 'ethers';

import { DIP_24_IPFS_HASH } from '../../src/lib/constants';
import { describeContract, TestContext } from '../helpers/describe-contract';

// LP rewards should be reduced by 50% (115068500000000000000000 => 575343000000000000000000)
// Trader rewards should stay the same (1582192000000000000000000)
// Alpha parameter show stay the same (0)

function init() { }

describeContract('update-merkle-distributor-rewards-parameters-dip24', init, (ctx: TestContext) => {

it('Proposal IPFS hash is correct', async () => {
const updateMerkleDistributorRewardsParametersDIP24Proposal = 14;
const proposal = await ctx.governor.getProposalById(updateMerkleDistributorRewardsParametersDIP24Proposal);
expect(proposal.ipfsHash).to.equal(DIP_24_IPFS_HASH);
});

it('Merkle distributor reward parameters are updated for DIP 24', async () => {
const [
lpRewardsAmount,
traderRewardsAmount,
alphaParameter,
]: [
BigNumber,
BigNumber,
BigNumber,
] = await ctx.merkleDistributor.getRewardsParameters();


expect(lpRewardsAmount.toString()).to.equal('575343000000000000000000');
expect(traderRewardsAmount.toString()).to.equal('1582192000000000000000000');
expect(alphaParameter).to.equal(0);
});
});

0 comments on commit 6ba80f4

Please sign in to comment.