2024-01-31 15:04:44 +03:00
|
|
|
const { ethers, network } = require("hardhat");
|
|
|
|
const { time } = require("@nomicfoundation/hardhat-toolbox/network-helpers");
|
|
|
|
|
|
|
|
const stakingAddr = "0x5B3f656C80E8ddb9ec01Dd9018815576E9238c29";
|
|
|
|
const governanceAddr = "0x5efda50f22d34F262c29268506C5Fa42cB56A1Ce";
|
|
|
|
const tornAddr = "0x77777FeDdddFfC19Ff86DB637967013e6C6A116C";
|
|
|
|
|
|
|
|
async function getManyEth(addr) {
|
2024-02-10 21:43:54 +03:00
|
|
|
await network.provider.send("hardhat_setBalance", [addr, "0x111166630153483537"]);
|
2024-01-31 15:04:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
async function getPermitSignature(signer, tokenContract, spender, value, deadline) {
|
|
|
|
const [nonce, name, version, chainId] = await Promise.all([
|
|
|
|
tokenContract.nonces(signer.address),
|
|
|
|
tokenContract.name(),
|
|
|
|
"1",
|
|
|
|
tokenContract.chainID(),
|
|
|
|
]);
|
|
|
|
|
|
|
|
const domain = {
|
|
|
|
name,
|
|
|
|
version,
|
|
|
|
chainId,
|
|
|
|
verifyingContract: tornAddr,
|
|
|
|
};
|
|
|
|
const types = {
|
|
|
|
Permit: [
|
|
|
|
{
|
|
|
|
name: "owner",
|
|
|
|
type: "address",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "spender",
|
|
|
|
type: "address",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "value",
|
|
|
|
type: "uint256",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "nonce",
|
|
|
|
type: "uint256",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
name: "deadline",
|
|
|
|
type: "uint256",
|
|
|
|
},
|
|
|
|
],
|
|
|
|
};
|
|
|
|
const values = {
|
|
|
|
owner: signer.address,
|
|
|
|
spender,
|
|
|
|
value,
|
|
|
|
nonce,
|
|
|
|
deadline,
|
|
|
|
};
|
|
|
|
|
|
|
|
const signature = await signer.signTypedData(domain, types, values);
|
|
|
|
return ethers.Signature.from(signature);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function resetStateBeforeProposal() {
|
|
|
|
await network.provider.request({
|
|
|
|
method: "hardhat_reset",
|
|
|
|
params: [
|
|
|
|
{
|
|
|
|
forking: {
|
|
|
|
jsonRpcUrl: config.networks.hardhat.forking.url,
|
|
|
|
blockNumber: config.networks.hardhat.forking.blockNumber,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
],
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getTorn(signer) {
|
|
|
|
return await ethers.getContractAt(require("./abi/torn.abi.json"), tornAddr, signer);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getEnsRegistry() {
|
|
|
|
const ensAddr = "0x00000000000C2E074eC69A0dFb2997BA6C7d2e1e";
|
|
|
|
return await ethers.getContractAt(require("./abi/ensRegistry.abi.json"), ensAddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getEnsResolver(ensName) {
|
|
|
|
const ensRegistry = await getEnsRegistry();
|
|
|
|
const resolverAddr = await ensRegistry.resolver(ethers.namehash(ensName));
|
|
|
|
return await ethers.getContractAt(require("./abi/ensResolver.abi.json"), resolverAddr);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function resolveAddr(ensName) {
|
|
|
|
if (ethers.isAddress(ensName)) return ensName;
|
|
|
|
const ensResolver = await getEnsResolver(ensName);
|
|
|
|
|
|
|
|
return await ensResolver.addr(ethers.namehash(ensName));
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getProxyImplAddr(proxyAddr) {
|
|
|
|
const implementation = await ethers.provider.getStorage(
|
|
|
|
proxyAddr,
|
|
|
|
"0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc",
|
|
|
|
);
|
|
|
|
const [implementationAddr] = new ethers.AbiCoder().decode(["address"], implementation);
|
|
|
|
|
|
|
|
return implementationAddr;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getGovernance(signer) {
|
|
|
|
return await ethers.getContractAt(require("./abi/governance.abi.json"), governanceAddr, signer);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function getAirdrop(airdropAddr, signer) {
|
|
|
|
return await ethers.getContractAt(require("./abi/airdrop.abi.json"), airdropAddr, signer);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function signerLockInGov(tornAmount, signer) {
|
|
|
|
if (!signer) signer = (await ethers.getSigners())[0];
|
2024-02-10 21:43:54 +03:00
|
|
|
if (tornAmount == "quorum") tornAmount = await (await getGovernance()).QUORUM_VOTES();
|
2024-01-31 15:04:44 +03:00
|
|
|
|
|
|
|
const governanceSigner = await ethers.getImpersonatedSigner(governanceAddr);
|
|
|
|
const torn = await getTorn(governanceSigner);
|
|
|
|
await torn.transfer(signer.address, tornAmount);
|
|
|
|
await getManyEth(signer.address);
|
|
|
|
const governance = await getGovernance(signer);
|
|
|
|
const deadline = ethers.MaxUint256;
|
|
|
|
const { v, r, s } = await getPermitSignature(signer, torn, governanceAddr, tornAmount, deadline);
|
|
|
|
await governance.lock(signer.address, tornAmount, deadline, v, r, s);
|
|
|
|
|
|
|
|
return signer;
|
|
|
|
}
|
|
|
|
|
|
|
|
async function executeNewProposal(proposalAddr) {
|
|
|
|
const governance = await getGovernance();
|
|
|
|
const quorum = await governance.QUORUM_VOTES();
|
|
|
|
const stakerSigner = await signerLockInGov(quorum);
|
|
|
|
const governanceContract = await getGovernance(stakerSigner);
|
|
|
|
await governanceContract.propose(proposalAddr, "");
|
|
|
|
const proposalId = await governanceContract.proposalCount();
|
|
|
|
await time.increase(60 * 60);
|
|
|
|
await governanceContract.castVote(proposalId, true);
|
|
|
|
await time.increase(60 * 60 * 24 * 7 + 60);
|
2024-02-10 21:43:54 +03:00
|
|
|
await getManyEth(stakerSigner.address);
|
2024-01-31 15:04:44 +03:00
|
|
|
await governanceContract.execute(proposalId);
|
|
|
|
await time.increase(60 * 60 * 24 * 4);
|
|
|
|
await governanceContract.unlock(quorum);
|
|
|
|
const torn = await getTorn(stakerSigner);
|
|
|
|
await torn.transfer(governanceAddr, quorum);
|
|
|
|
}
|
|
|
|
|
|
|
|
async function deployAndExecuteProposal() {
|
2024-02-10 21:43:54 +03:00
|
|
|
const recipientsFactory = await ethers.getContractFactory("AirdropRecipients");
|
|
|
|
const airdropRecipientsContract = await recipientsFactory.deploy(require("../data/airdropRecipients.json"));
|
|
|
|
const recipientStorageAddr = await airdropRecipientsContract.getAddress();
|
|
|
|
|
2024-01-31 15:04:44 +03:00
|
|
|
const airdropFactory = await ethers.getContractFactory("SablierAirdrop");
|
|
|
|
const airdrop = await airdropFactory.deploy();
|
|
|
|
const airdropAddr = await airdrop.getAddress();
|
|
|
|
|
|
|
|
const proposalFactory = await ethers.getContractFactory("Proposal");
|
2024-02-10 21:43:54 +03:00
|
|
|
const proposal = await proposalFactory.deploy(airdropAddr, recipientStorageAddr);
|
2024-01-31 15:04:44 +03:00
|
|
|
const deployedProposalAddr = await proposal.getAddress();
|
|
|
|
|
|
|
|
await executeNewProposal(deployedProposalAddr);
|
|
|
|
|
2024-02-10 21:43:54 +03:00
|
|
|
const airdropContract = await getAirdrop(airdropAddr, await ethers.getImpersonatedSigner(governanceAddr));
|
|
|
|
return { airdropAddr, airdropContract, airdropRecipientsContract };
|
2024-01-31 15:04:44 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
resetStateBeforeProposal,
|
|
|
|
deployAndExecuteProposal,
|
|
|
|
getGovernance,
|
|
|
|
getEnsRegistry,
|
|
|
|
getEnsResolver,
|
|
|
|
resolveAddr,
|
|
|
|
getProxyImplAddr,
|
|
|
|
governanceAddr,
|
|
|
|
getManyEth,
|
|
|
|
tornAddr,
|
|
|
|
getTorn,
|
|
|
|
stakingAddr,
|
|
|
|
getPermitSignature,
|
|
|
|
signerLockInGov,
|
|
|
|
executeNewProposal,
|
|
|
|
};
|