참고: 자금 금액은 ERC20 표준에 따라 10^18을 곱해야 합니다. 해당 금액이 아직 정해지지 않은 경우, 임시 금액을 사용할 수 있습니다(예: 10 → 10000000000000000000).
다른 리포지토리에서 승인된 DIP를 참조할 IPFS 해시 변수를 src/lib/constants.ts에 추가합니다.
src/lib/constants.ts
...
// Add a link to where the hash can be found
export const DIP_NUMBER_IPFS_HASH = '0x0000000000000000000000000000000000000000000000000000000000000000';
참고: DIP가 아직 게시되지 않은 경우 테스트에 임시 값을 사용할 수 있습니다(예: ‘0x0000000000000000000000000000000000000000000000000000000000000000’)\
4. 계획안 코드
_src/migrations_에, proposal-name.ts와 같이 계획안 이름의 새 파일을 다시 만들고 해당 파일에 다음 코드를 작성합니다.
a. 맨 위에 필요한 import를 추가합니다.
src/migrations/proposal-name.ts
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';
b. import 아래에서 계획안 이름을 사용하여 새 함수를 만들고 다음 코드를 두 개의 고유한 변수와 함께 추가합니다.
destinationAddress → 자금을 받는 주소가 됩니다.
deployConfig.PROPOSAL_FUNDING_AMOUNT → 이전에 생성한 변수로 송금할 금액을 결정합니다.
tasks/deployment/proposal-name.ts
import { types } from 'hardhat/config';
import mainnetAddresses from '../../src/deployed-addresses/mainnet.json';
import { hardhatTask } from '../../src/hre';
import { DIP_NUMBER_IPFS_HASH } from '../../src/lib/constants';
import { createProposalNameProposal } from '../../src/migrations/proposal-name';
b. hardhat 작업을 생성하고 작업 시작 줄에 있는 계획안 정보로 채웁니다.
'deploy:proposal-name:'에 있는 proposal-name을 교체하고 ‘Proposal Description’을 간략한 설명으로 교체합니다.
마지막 줄은 계획안 코드에서 가져온 함수를 호출하므로 수정이 필요합니다.
tasks/deployment/proposal-name.ts
hardhatTask('deploy:proposal-name', 'Proposal Description.')
.addParam('proposalIpfsHashHex', 'IPFS hash for the uploaded DIP describing the proposal', DIP_NUMBER_IPFS_HASH, types.string)
.addParam('dydxTokenAddress', 'Address of the deployed DYDX token contract', mainnetAddresses.dydxToken, 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('communityTreasuryAddress', 'Address of the deployed community treasury contract', mainnetAddresses.communityTreasury, types.string)
.setAction(async (args) => {
await createProposalNameProposal(args);
});
6. 테스트 빌드
이제 코드를 배포할 준비가 되었으므로 계획안을 중심으로 몇 가지 테스트를 빌드할 차례입니다. 로컬에서 테스트를 진행하고 메인넷 포크를 사용하여 계획안이 온체인에서 실행되도록 시뮬레이션합니다.
a. 계획안 테스트 추가
test/migrations에 proposal-name.ts과 같이 계획안 이름이 들어간 새 파일을 다시 추가하고 해당 파일에 다음 코드를 포함시킵니다.
마지막 else 루프 외부에 있는 getDeployedContractsForTest() 함수에 이 함수를 추가합니다.
test/helpers/get-deployed-contracts-for-test.ts
async function getDeployedContractsForTest(): Promise<AllDeployedContracts> {
if (!config.isHardhat()) {
return getAllContracts();
}
let deployedContracts: AllDeployedContracts;
if (config.FORK_MAINNET) {
deployedContracts = await getAllContracts();
} else {
deployedContracts = await deployContractsForTest();
// Execute the proposals which have already been executed on mainnet.
//
// The proposals will be executed when running on a local test network,
// but will not be executed when running on a mainnet fork.
await executeSafetyModuleRecoveryProposalsForTest(deployedContracts);
await executeStarkProxyProposalForTest(deployedContracts);
await executeGrantsProgramProposalForTest(deployedContracts);
await executeGrantsProgramv15ProposalForTest(deployedContracts);
await executeWindDownBorrowingPoolProposalForTest(deployedContracts);
await executeUpdateMerkleDistributorRewardsParametersProposalForTest(deployedContracts);
await executeWindDownSafetyModuleProposalForTest(deployedContracts);
}
await executeProposalNameProposalForTest(deployedContracts);
// Execute the proposals which have not yet been executed on mainnet.
await configureForTest(deployedContracts);
return deployedContracts;
}
d. 최종 테스트 파일
마지막으로 모의 계획안을 실행한 후 IPFS 해시와 다중 서명의 잔액에 대한 테스트를 추가하여 모든 것이 예상대로 종료되는지 확인합니다.
test/misc에 계획안 이름이 proposal-name-proposal.spec.ts인 새 파일을 추가하고 다음 두 테스트로 채웁니다.
DIP_NUMBER_IPFS_HASH를 통해 lib에서 IPFS 해시를 가져옵니다.
ProposalNameId를 사용하여 다음 번 proposalId 번호를 하드코딩합니다.
해시 상수로 계획안 해시를 확인합니다.
PROPOSAL_NAME_ADDRESS를 확인하여 PROPOSAL_FUNDING_AMOUNT의 예상 잔액이 있는지 확인합니다.
참고: 이 주소에 이미 DYDX가 있는 경우 테스트를 통과하려면 잔액에 하드코딩해야 합니다.
test/misc/proposal-name-proposal.spec.ts
import { expect } from 'chai';
import { DIP_NUMBER_IPFS_HASH } from '../../src/lib/constants';
import { describeContract, TestContext } from '../helpers/describe-contract';
function init() {}
describeContract('proposal-name', init, (ctx: TestContext) => {
it('Proposal IPFS hash is correct', async () => {
const ProposalNameId = #;
const proposal = await ctx.governor.getProposalById(ProposalNameId);
expect(proposal.ipfsHash).to.equal(DIP_NUMBER_IPFS_HASH);
});
it('Destination receives tokens from the community treasury', async () => {
const balance = await ctx.dydxToken.balanceOf(ctx.config.PROPOSAL_NAME_ADDRESS);
expect(balance).to.equal(ctx.config.PROPOSAL_FUNDING_AMOUNT);
});
});
7. PR 제출
이러한 모든 코드 변경이 완료되고 로컬에 저장되면 분기된 리포지토리에 커밋하고 dYdX 리포지토리에 대한 PR을 열어 다음과 같이 검토할 수 있습니다.