Technischer Leitfaden zur Erstellung eines Ausgabenvorschalgs für die dYdX Community
Ein technischer Schritt-für-Schritt-leitfaden zur Erstellung eines Vorschlags zur Übertragung von ethDYDX aus Mitteln der Community an eine Zieladresse.
Reverie hat einen umfassenden, technischen Leitfaden für die Einreichung eines Governance-Vorschlags zur Übertragung von $ethDYDX aus Mitteln der Community durch eine Pull-Anfrage in das dYdX Governance-Contracts Repository zusammengestellt.
Um diesen Vorschlag zu erstellen, muss ein Mitglied der dYdX-Community über mindestens 5 Mio Governance-Token (0,5 % des Gesamtangebots) an Vorschlagsrechten (Vorschlagsschwellenwert für eine kurzzeiitige Wahl) verfügen.
Vorläufige Anforderungen
Die folgenden Schritte müssen vor der Fertigstellung der Pull-Anfrage abgeschlossen werden:
Lebenszyklus des Vorschlags Das DRC muss gemäß der Vorschlagsvorlage gepostet werden und es muss eine erfolgreiche Snapshot-Abstimmung erfolgen.
Zieladresse: Die Zieladresse muss im Voraus generiert werden. Wenn die Zieladresse eine Multi-Sig-Adresse ist, muss das Multi-Sig-Wallet erstellt werden.
GitHub-Konto: Ein GitHub-Konto, um das Repository zu spalten.
Übertragungsmenge (optional): Vorzugsweise wurde die angeforderte Übertragungsmenge schon vor der Pull-Anfrage festgelegt. Wenn allerdings ein fiktiver Betrag verwendet wird, kann es als letzter Schritt vor der Genehmigung erfolgen.
DIP-IPFS-Hash (optional): Wenn der Übertragungsbetrag bekannt ist, sollte das DIP abgeschlossen und zum IPFS verschoben werden, um das Hash zu generieren. Es kann jedoch als ein letzter Schritt vor der Genehmigung festgelegt werden, wenn der Betrag noch nicht ermittelt wurde.
Fügen Sie in src/config/index.ts zwei neue Variablen zur configSchema-Konstante hinzu, die für Testzwecke verwendet werden. Ändern Sie in den folgenden Code-Blocks die Felder „VORSCHLAG_NAME“ und „VORSCHLAG“ in den Namen des eingereichten Vorschlags.
Hinweis: Der Finanzierungsbetrag muss gemäß ERC20 **mit 10^18 multipliziert **werden. Wenn der Betrag noch nicht bekannt ist, kann auch ein temporärer Betrag verwendet werden (z. B. 10 → 10 000 000 000 000 000 000).
Fügen Sie in src/lib/constants.ts die IPFS-Hash-Variable hinzu, die auf das im anderen Repository genehmigte DIP verweist:
src/lib/constants.ts...// Add a link to where the hash can be foundexportconstDIP_NUMBER_IPFS_HASH='0x0000000000000000000000000000000000000000000000000000000000000000';
Hinweis: Wenn das DIP noch nicht veröffentlicht wurde, kannn zum Test ein temporärer Wert verwendet werden (z. B. „0x0 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000 000“)\
4. Vorschlags-Code
Erstellen Sie in src/migrations eine neue Datei, benannt nach dem Vorschlag → Vorschlag-name.ts und tragen Sie den folgenden Code ein:
b. Erstellen Sie eine neue Funktion unter Verwendung des Vorschlagnamens unter den Importen und fügen Sie folgenden Code mit zwei einziartigen Variablen hinzu:
Zieladresse → diese Adresse wird die Finanzierung erhalten
deployConfig.PROPOSAL_FUNDING_AMOUNT → dies ist die Variable, die wir zuvor erstellt haben, mit der die zu übertragende Menge festgelegt wird
src/migrations/proposal-name.tsexportasyncfunctioncreateProposalNameProposal({ proposalIpfsHashHex, dydxTokenAddress, governorAddress, shortTimelockAddress, communityTreasuryAddress, destinationAddress,// This is the address that will receive the funding signer,}: { proposalIpfsHashHex:string, dydxTokenAddress:string, governorAddress:string, shortTimelockAddress:string, communityTreasuryAddress:string, destinationAddress:string, signer?:SignerWithAddress,}) {consthre=getHre();constdeployConfig=getDeployConfig();constdeployer= signer ||awaitgetDeployerSigner();constdeployerAddress=deployer.address;log(`Creating proposal with proposer ${deployerAddress}.\n`);constgovernor=awaitnewDydxGovernor__factory(deployer).attach(governorAddress);constproposalId=awaitgovernor.getProposalsCount();constproposal:Proposal= [ shortTimelockAddress, [communityTreasuryAddress], ['0'], ['transfer(address,address,uint256)'], [hre.ethers.utils.defaultAbiCoder.encode( ['address','address','uint256'], [dydxTokenAddress, destinationAddress,deployConfig.PROPOSAL_FUNDING_AMOUNT], )], [false], proposalIpfsHashHex, ];awaitwaitForTx(awaitgovernor.create(...proposal));return { proposalId, };}
5. Bereitstellungsaufgabe
Mit dem erstellten Vorschlag können wir die Bereitstellung schreiben, mit der die erforderlichen Transaktions- und Anrufdaten erstellt werden, um den Vorschlag einzureichen.
Erstellen Sie in tasks/deployment, eine neue Datei mit demselben Namen, der auch für den Vorchlags-Code verwendet wurde → Vorschlag-name.ts und tragen Sie den folgenden Code ein:
a. Fügen Sie die benötigten Importe mit den folgenden Variablen hinzu:
DIP_NUMBER_IPFS_HASH → Dies ist die Variable, die wir in lib/constants hinzufügen.
createProposalNameProposal → Dies ist die Funktion, die wir in /src/migrations/proposal-name erstellt haben.
b. Erstellen Sie die Hardhat-Aufgabe und tragen Sie die Vorschlagsdaten in die Eröffnungszeile der Aufgabe ein.
Ersetzen Sie den Vorschlag-name in „deploy:proposal-name: und ersetzen Sie ihn mit einer Beschreibung in „Proposal Description“.
Die letzte Zeile ruft die Funktion auf, die Sie aus dem Vorschlags-Code importiert haben, muss also angepasst werden.
tasks/deployment/proposal-name.tshardhatTask('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) => {awaitcreateProposalNameProposal(args); });
6. Tests durchführen
Nachdem der Code nun für die Bereitstellung bereit ist, wird es Zeit, einige Tests rund um den Vorschlag zu erstellen. Das Testen erfolgt lokal unter Verwendung eines Mainnet-Forks, um zu simulieren, dass ein Vorschlag in der Chain ausgeführt wird.
a. Vorschlagstests hinzufügen
Fügen Sie in Test/Migrationen erneut eine neue Datei mit dem Vorschlagnamen → proposal-name.ts hinzu und tragen Sie den folgenden Code ein:
Fügen Sie die benötigten Importe einschließlich der Vorschlagsfunktionen hinzu:
createProposalNameProposal → Dies ist die Funktion, die wir in /src/migrations/proposal-name erstellt haben. \
MOCK_PROPOSAL_IPFS_HASH → wir verwenden für Testzwecke ein Attrappen-Hash
Fügen Sie Tests für beide Funktionen hinzu, indem Sie eine allgemeine Testfunktion erstellen → executeProposalNameProposalForTest, ersetzen Sie den Namen, sodass er zum Vorschlag passt
Wir rufen auch die zuvor erstellte Konfigurationsvariable TEST_PROPOSAL_NAME_TRUST_WITH_PROPOSAL und die PROPOSAL_NAME_ADDRESS von deployConfig auf.
...exportasyncfunctionexecuteProposalNameProposalForTest( deployedContracts:AllDeployedContracts,) {constdeployConfig=getDeployConfig();if (config.TEST_PROPOSAL_NAME_TRUST_WITH_PROPOSAL) {awaitfundProposalNameViaProposal({ dydxTokenAddress:deployedContracts.dydxToken.address, governorAddress:deployedContracts.governor.address, shortTimelockAddress:deployedContracts.shortTimelock.address, communityTreasuryAddress:deployedContracts.communityTreasury.address, destinationAddress:deployConfig.PROPOSAL_NAME_ADDRESS, }); } else {awaitfundProposalNameNoProposal({ dydxTokenAddress:deployedContracts.dydxToken.address, shortTimelockAddress:deployedContracts.shortTimelock.address, communityTreasuryAddress:deployedContracts.communityTreasury.address, destinationAddress:deployConfig.PROPOSAL_NAME_ADDRESS, }); }}...// put this above the configureForTest function
c. Fügen Sie einen Vertrag zu Testhelfern hinzu
Fügen Sie in test/helpers/get-deployed-contracts-for-test.ts die oben erstellte Funktion hinzu, damit die Tests im Mainnet-Fork ausgeführt werden
Importieren Sie die Funktion executeProposalNameProposalForTest aus derMigrationsdatei:
Fügen Sie die Funktion zu getDeployedContractsForTest() hinzu, außerhalb der letzten else-Schleife:
test/helpers/get-deployed-contracts-for-test.tsasyncfunctiongetDeployedContractsForTest():Promise<AllDeployedContracts> {if (!config.isHardhat()) {returngetAllContracts(); }let deployedContracts:AllDeployedContracts;if (config.FORK_MAINNET) { deployedContracts =awaitgetAllContracts(); } else { deployedContracts =awaitdeployContractsForTest();// 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.awaitexecuteSafetyModuleRecoveryProposalsForTest(deployedContracts);awaitexecuteStarkProxyProposalForTest(deployedContracts);awaitexecuteGrantsProgramProposalForTest(deployedContracts);awaitexecuteGrantsProgramv15ProposalForTest(deployedContracts);awaitexecuteWindDownBorrowingPoolProposalForTest(deployedContracts);awaitexecuteUpdateMerkleDistributorRewardsParametersProposalForTest(deployedContracts);awaitexecuteWindDownSafetyModuleProposalForTest(deployedContracts); }awaitexecuteProposalNameProposalForTest(deployedContracts);// Execute the proposals which have not yet been executed on mainnet.awaitconfigureForTest(deployedContracts);return deployedContracts;}
d. Endgültige Testdatei
Schlussendlich fügen wir einen Test sowohl zum IPFS-Hash als auch zur Bilanz des Multi-Sig nach dem Attrappenvorschlag hinzu, um sicherzustellen, dass alles wie erwartet zu Ende geht.
Fügen Sie in test/misc eine neue Datei mit dem Vorschlagsnamen → proposal-name-proposal.spec.ts beschriftet, hinzu und tragen Sie diese zwei Tests ein:
Wir importieren dieses IPFS-Hash aus derBibliothek durch DIP_NUMBER_IPFS_HASH
wir codieren die nächste Vorschlags-Id unter Verwendung von ProposalNameId
wir überprüfen das Vorschlags-Hash mit dem konstanten Hash
wir überprüfen die Adresse PROPOSAL_NAME_ADDRESS, um zu sehen, ob es eine ausgeglichene Bilanz des Betrags PROPOSAL_FUNDING_AMOUNT hat
Hinweis: wenn diese Adress bereits DYDX hat, müssen Sie fest einprogrammieren, damti die Bilanz den Test besteht
test/misc/proposal-name-proposal.spec.tsimport { expect } from'chai';import { DIP_NUMBER_IPFS_HASH } from'../../src/lib/constants';import { describeContract, TestContext } from'../helpers/describe-contract';functioninit() {}describeContract('proposal-name', init, (ctx:TestContext) => {it('Proposal IPFS hash is correct',async () => {constProposalNameId= #;constproposal=awaitctx.governor.getProposalById(ProposalNameId);expect(proposal.ipfsHash).to.equal(DIP_NUMBER_IPFS_HASH); });it('Destination receives tokens from the community treasury',async () => {constbalance=awaitctx.dydxToken.balanceOf(ctx.config.PROPOSAL_NAME_ADDRESS);expect(balance).to.equal(ctx.config.PROPOSAL_FUNDING_AMOUNT); });});
7. Die Pull-Anfrage einreichen
Nachdem alle diese Codeveränderungen gemacht wurden, können wir an das geforkte Repiository übergeben und eine Pulll-Anfrage an das dYdX für Überprüfer öffnen:
a. Bestätigen Sie die Änderungen durch die Befehlszeile