forked from mico/idle_moloch
842 lines
27 KiB
TypeScript
842 lines
27 KiB
TypeScript
import * as fs from "fs";
|
|
import { ethers } from "ethers";
|
|
import { task } from "hardhat/config";
|
|
|
|
import { BigNumber } from "@ethersproject/bignumber";
|
|
import { encodeMultiSend, MetaTransaction } from "@gnosis.pm/safe-contracts";
|
|
|
|
import { deployments as currentDeployments } from '../src/addresses/deployed';
|
|
import { getSetupAddresses } from '../src/addresses/setup';
|
|
|
|
|
|
type SupportedNetwork = keyof typeof currentDeployments[0]['v103'];
|
|
|
|
const DEBUG = true;
|
|
|
|
task(
|
|
"generate",
|
|
"Create a mnemonic for builder deploys",
|
|
async (_, { ethers }) => {
|
|
const bip39 = require("bip39");
|
|
const hdkey = require("ethereumjs-wallet/hdkey");
|
|
const mnemonic = bip39.generateMnemonic();
|
|
if (DEBUG) console.log("mnemonic", mnemonic);
|
|
const seed = await bip39.mnemonicToSeed(mnemonic);
|
|
if (DEBUG) console.log("seed", seed);
|
|
const hdwallet = hdkey.fromMasterSeed(seed);
|
|
const wallet_hdpath = "m/44'/60'/0'/0/";
|
|
const account_index = 0;
|
|
let fullPath = wallet_hdpath + account_index;
|
|
if (DEBUG) console.log("fullPath", fullPath);
|
|
const wallet = hdwallet.derivePath(fullPath).getWallet();
|
|
const privateKey = "0x" + wallet._privKey.toString("hex");
|
|
if (DEBUG) console.log("privateKey", privateKey);
|
|
var EthUtil = require("ethereumjs-util");
|
|
const address =
|
|
"0x" + EthUtil.privateToAddress(wallet._privKey).toString("hex");
|
|
console.log(
|
|
"🔐 Account Generated as " +
|
|
address +
|
|
" and set as mnemonic in packages/hardhat"
|
|
);
|
|
console.log(
|
|
"💬 Use 'yarn run account' to get more information about the deployment account."
|
|
);
|
|
|
|
fs.writeFileSync("../" + address + ".txt", mnemonic.toString());
|
|
fs.writeFileSync("../mnemonic.txt", mnemonic.toString());
|
|
}
|
|
);
|
|
|
|
/* DAO tasks */
|
|
/* TODO: DAO amin tasks */
|
|
|
|
task("baal:delegate", "Delegate shares")
|
|
.addParam("dao", "Dao address")
|
|
.addParam("to", "delegate to")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baal = Baal.attach(taskArgs.dao);
|
|
const Shares = await hre.ethers.getContractFactory("SharesERC20");
|
|
const shares = Shares.attach(baal.address);
|
|
const delegateVotes = await shares.delegate(taskArgs.to);
|
|
console.log("Delegate votes txhash:", delegateVotes.hash);
|
|
});
|
|
|
|
task("baal:ragequit", "Ragequit shares and/or loot")
|
|
.addParam("dao", "Dao address")
|
|
.addParam("to", "RQ to")
|
|
.addParam("shares", "number of shares")
|
|
.addParam("loot", "number of loot")
|
|
.addParam(
|
|
"tokens",
|
|
'the token addresses (array) (escape quotes) (no spaces) ex [\\"0x123...\\"]'
|
|
)
|
|
.setAction(async (taskArgs, hre) => {
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baal = Baal.attach(taskArgs.dao);
|
|
const tokens = JSON.parse(taskArgs.tokens);
|
|
const ragequitAction = await baal.ragequit(
|
|
taskArgs.to,
|
|
taskArgs.shares,
|
|
taskArgs.loot,
|
|
tokens
|
|
);
|
|
console.log("Ragequit txhash:", ragequitAction.hash);
|
|
});
|
|
|
|
task("baal:tribute-prop", "Approve token and make a tribute proposal")
|
|
.addParam("dao", "Dao address")
|
|
.addParam("minion", "Tribute Minion address")
|
|
.addParam("token", "Tribute token address")
|
|
.addParam("amount", "Tribute token amount")
|
|
.addParam("shares", "Tribute shares requested")
|
|
.addParam("loot", "Tribute loot requested")
|
|
.addParam("baalGas", "Tribute baal gas date. 0 for none")
|
|
.addParam("expiration", "Tribute expiration date. 0 for ignore")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baal = Baal.attach(taskArgs.dao);
|
|
const Token = await hre.ethers.getContractFactory("TestERC20");
|
|
const token = Token.attach(taskArgs.token);
|
|
const Minion = await hre.ethers.getContractFactory("TributeMinion");
|
|
const minion = Minion.attach(taskArgs.minion);
|
|
const countBefore = await baal.proposalCount();
|
|
console.log("countBefore", countBefore);
|
|
const deployers = await hre.ethers.getSigners();
|
|
const address = await deployers[0].getAddress();
|
|
// approve
|
|
const approve = await token.approve(taskArgs.minion, taskArgs.amount);
|
|
const encoded = await minion.encodeTributeProposal(
|
|
taskArgs.dao,
|
|
taskArgs.shares,
|
|
taskArgs.loot,
|
|
address,
|
|
countBefore + 1,
|
|
taskArgs.minion
|
|
);
|
|
console.log("*****encoded proposal******");
|
|
console.log(encoded);
|
|
console.log("***************************");
|
|
|
|
const tributeProposal = await minion.submitTributeProposal(
|
|
taskArgs.dao,
|
|
taskArgs.token,
|
|
taskArgs.amount,
|
|
taskArgs.shares,
|
|
taskArgs.loot,
|
|
taskArgs.expiration,
|
|
taskArgs.baalGas,
|
|
"tribute from cli"
|
|
);
|
|
console.log("Tribute proposal submitted txhash:", tributeProposal.hash);
|
|
});
|
|
|
|
task("baal:cancel-prop", "Cancel a proposal")
|
|
.addParam("dao", "Dao address")
|
|
.addParam("id", "Proposal ID")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baal = Baal.attach(taskArgs.dao);
|
|
// TODO: pull event data from etherscan
|
|
const cancelProposal = await baal.cancelProposal(taskArgs.id);
|
|
console.log("Proposal processed txhash:", cancelProposal.hash);
|
|
});
|
|
|
|
task("baal:process-prop", "Process a proposal")
|
|
.addParam("dao", "Dao address")
|
|
.addParam("id", "Proposal ID")
|
|
.addParam("data", "the data, need to get this from the submit events")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baal = Baal.attach(taskArgs.dao);
|
|
// TODO: pull event data from etherscan
|
|
const processProposal = await baal.processProposal(
|
|
taskArgs.id,
|
|
taskArgs.data
|
|
);
|
|
console.log("Proposal processed txhash:", processProposal.hash);
|
|
});
|
|
|
|
task("baal:vote-prop", "Vote on a proposal")
|
|
.addParam("dao", "Dao address")
|
|
.addParam("id", "Proposal ID")
|
|
.addParam("approve", "true is yes and false is no")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baal = Baal.attach(taskArgs.dao);
|
|
const submitVote = await baal.submitVote(
|
|
taskArgs.id,
|
|
taskArgs.approve === "true"
|
|
);
|
|
console.log("Proposal voted on txhash:", submitVote.hash);
|
|
});
|
|
|
|
task("baal:sponsor-prop", "Status of a proposal")
|
|
.addParam("dao", "Dao address")
|
|
.addParam("id", "Proposal ID")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baal = Baal.attach(taskArgs.dao);
|
|
const proposal = await baal.sponsorProposal(taskArgs.id);
|
|
console.log("Proposal sponsored txhash:", proposal.hash);
|
|
});
|
|
|
|
task("baal:status-prop", "Status of a proposal")
|
|
.addParam("dao", "Dao address")
|
|
.addParam("id", "Proposal ID")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baal = Baal.attach(taskArgs.dao);
|
|
const proposal = await baal.proposals(taskArgs.id);
|
|
console.log("Proposal status:", proposal);
|
|
});
|
|
|
|
task("baal:getlatest-prop", "Current Proposal info")
|
|
.addParam("dao", "Dao address")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baal = Baal.attach(taskArgs.dao);
|
|
const count = await baal.functions.proposalCount();
|
|
const lastSponsored = await baal.latestSponsoredProposalId();
|
|
console.log("the current proposal count is:", count);
|
|
console.log("the last proposal sponsored is:", lastSponsored);
|
|
});
|
|
|
|
task("baal:member-prop", "Submits a new member proposal")
|
|
.addParam("dao", "Dao address")
|
|
.addParam("applicant", "applicant address")
|
|
.addParam("shares", "number shares")
|
|
.addParam("loot", "number loot")
|
|
.addParam(
|
|
"expiration",
|
|
"seconds after grace that proposal expires, 0 for none"
|
|
)
|
|
.addOptionalParam("meta", "updated meta data")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const { deployments, getChainId, network } = hre;
|
|
const chainId = await getChainId();
|
|
const _addresses = await getSetupAddresses(chainId, network, deployments);
|
|
|
|
const encodeMultiAction2 = (
|
|
multisend: any,
|
|
actions: string[],
|
|
tos: string[],
|
|
values: BigNumber[],
|
|
operations: number[]
|
|
) => {
|
|
let metatransactions: MetaTransaction[] = [];
|
|
for (let index = 0; index < actions.length; index++) {
|
|
metatransactions.push({
|
|
to: tos[index],
|
|
value: values[index],
|
|
data: actions[index],
|
|
operation: operations[index],
|
|
});
|
|
}
|
|
const encodedMetatransactions = encodeMultiSend(metatransactions);
|
|
const multi_action = multisend.interface.encodeFunctionData("multiSend", [
|
|
encodedMetatransactions,
|
|
]);
|
|
return multi_action;
|
|
};
|
|
|
|
const MultisendContract = await hre.ethers.getContractFactory("MultiSend");
|
|
const multisend = MultisendContract.attach(
|
|
_addresses.gnosisMultisendLibrary
|
|
);
|
|
|
|
const block = await hre.ethers.provider.getBlock("latest");
|
|
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baal = Baal.attach(taskArgs.dao);
|
|
const countBefore = await baal.proposalCount();
|
|
console.log("countBefore", countBefore);
|
|
|
|
const mintLootAction = baal.interface.encodeFunctionData("mintLoot", [
|
|
[taskArgs.applicant],
|
|
[taskArgs.loot],
|
|
]);
|
|
const mintSharesAction = baal.interface.encodeFunctionData(
|
|
"mintShares",
|
|
[[taskArgs.applicant], [taskArgs.shares]]
|
|
);
|
|
const metadataConfig = {
|
|
CONTENT: taskArgs.meta || '{"name":"test proposal"}',
|
|
TAG: "daohaus.proposal.metadata",
|
|
};
|
|
// const posterFactory = await hre.ethers.getContractFactory("Poster");
|
|
// const poster = (await posterFactory.attach(_addresses.poster)) as Poster;
|
|
// const postMetaData = await poster.interface.encodeFunctionData("post", [
|
|
// metadataConfig.CONTENT,
|
|
// metadataConfig.TAG,
|
|
// ]);
|
|
// const posterFromBaal = await baal.interface.encodeFunctionData(
|
|
// "executeAsBaal",
|
|
// [poster.address, 0, postMetaData]
|
|
// );
|
|
|
|
const now = block.timestamp;
|
|
const voting = await baal.votingPeriod();
|
|
const grace = await baal.gracePeriod();
|
|
|
|
const encodedAction = encodeMultiAction2(
|
|
multisend,
|
|
[mintLootAction, mintSharesAction],
|
|
[baal.address, baal.address],
|
|
[BigNumber.from(0), BigNumber.from(0)],
|
|
[0, 0, 0]
|
|
);
|
|
|
|
console.log("********encoded data*********");
|
|
console.log(encodedAction);
|
|
console.log("*****************************");
|
|
// TODO: poster should happen here probably, if in encodeAction it will run after processing
|
|
const submit = await baal.submitProposal(
|
|
encodedAction,
|
|
parseInt(taskArgs.expiration)
|
|
? now + voting + grace + parseInt(taskArgs.expiration)
|
|
: 0,
|
|
0,
|
|
metadataConfig.CONTENT // hre.ethers.utils.id("all hail baal")
|
|
);
|
|
console.log("tx:", submit.hash);
|
|
});
|
|
|
|
|
|
task("baal:shaman-prop", "Submits a new shman proposal")
|
|
.addParam("dao", "Dao address")
|
|
.addParam("shaman", "shaman address")
|
|
.addParam("permissions", "permission number")
|
|
.addParam(
|
|
"expiration",
|
|
"seconds after grace that proposal expires, 0 for none"
|
|
)
|
|
.addOptionalParam("meta", "updated meta data")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const { deployments, getChainId, network } = hre;
|
|
const chainId = await getChainId();
|
|
const _addresses = await getSetupAddresses(chainId, network, deployments);
|
|
|
|
const encodeMultiAction2 = (
|
|
multisend: any,
|
|
actions: string[],
|
|
tos: string[],
|
|
values: BigNumber[],
|
|
operations: number[]
|
|
) => {
|
|
let metatransactions: MetaTransaction[] = [];
|
|
for (let index = 0; index < actions.length; index++) {
|
|
metatransactions.push({
|
|
to: tos[index],
|
|
value: values[index],
|
|
data: actions[index],
|
|
operation: operations[index],
|
|
});
|
|
}
|
|
const encodedMetatransactions = encodeMultiSend(metatransactions);
|
|
const multi_action = multisend.interface.encodeFunctionData("multiSend", [
|
|
encodedMetatransactions,
|
|
]);
|
|
return multi_action;
|
|
};
|
|
|
|
const MultisendContract = await hre.ethers.getContractFactory("MultiSend");
|
|
const multisend = MultisendContract.attach(
|
|
_addresses.gnosisMultisendLibrary
|
|
);
|
|
|
|
const block = await hre.ethers.provider.getBlock("latest");
|
|
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baal = Baal.attach(taskArgs.dao);
|
|
const countBefore = await baal.proposalCount();
|
|
console.log("countBefore", countBefore);
|
|
|
|
const addShamanAction = baal.interface.encodeFunctionData("setShamans", [
|
|
[taskArgs.shaman],
|
|
[taskArgs.permissions],
|
|
]);
|
|
|
|
const metadataConfig = {
|
|
CONTENT: taskArgs.meta || '{"name":"test shaman proposal"}',
|
|
TAG: "daohaus.proposal.metadata",
|
|
};
|
|
|
|
const now = await block.timestamp;
|
|
const voting = await baal.votingPeriod();
|
|
const grace = await baal.gracePeriod();
|
|
|
|
const encodedAction = encodeMultiAction2(
|
|
multisend,
|
|
[addShamanAction],
|
|
[baal.address],
|
|
[BigNumber.from(0)],
|
|
[0, 0, 0]
|
|
);
|
|
|
|
console.log("********encoded data*********");
|
|
console.log(encodedAction);
|
|
console.log("*****************************");
|
|
const submit = await baal.submitProposal(
|
|
encodedAction,
|
|
parseInt(taskArgs.expiration)
|
|
? now + voting + grace + parseInt(taskArgs.expiration)
|
|
: 0,
|
|
0,
|
|
metadataConfig.CONTENT // hre.ethers.utils.id("all hail baal")
|
|
);
|
|
console.log("tx:", submit.hash);
|
|
});
|
|
|
|
/* example:
|
|
npx hardhat summon --factory 0xe2F42d9fd5C1a590F6c3d6b2A27802C0da93FEb7
|
|
--summoners [\"0xadc...\"]
|
|
--shares [\"10000000000000000000\"] --loot [\"10000000000000000000\"]
|
|
--sharespaused false --lootpaused false
|
|
--shaman 0xadc... --name gB447 --network goerli
|
|
*/
|
|
task("baal:summon", "Summons a new DAO")
|
|
.addParam("factory", "Dao factory address")
|
|
.addParam(
|
|
"summoners",
|
|
'the summoner addresses (array) (escape quotes) (no spaces) ex [\\"0x123...\\"]'
|
|
)
|
|
.addParam(
|
|
"shares",
|
|
"numnber of initial shares for summoners (string array, escape quotes)"
|
|
)
|
|
.addParam(
|
|
"loot",
|
|
"numnber of initial loot for summoners (string array, escape quotes)"
|
|
)
|
|
.addParam("sharespaused", "are shares transferable")
|
|
.addParam("lootpaused", "is loot transferable")
|
|
.addParam("shaman", "any initial shamans")
|
|
.addParam("name", "share token symbol")
|
|
.addOptionalParam("meta", "updated meta data")
|
|
.addOptionalParam("withsidecar", "add a vault (factory address)")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const { deployments, getChainId, network } = hre;
|
|
const chainId = await getChainId();
|
|
const _addresses = await getSetupAddresses(chainId, network, deployments);
|
|
|
|
const zeroAddress = ethers.constants.AddressZero;
|
|
const metadataConfig = {
|
|
CONTENT: taskArgs.meta || '{"name":"test"}',
|
|
TAG: "daohaus.summoner.daoProfile",
|
|
};
|
|
let summonerArr;
|
|
let lootArr;
|
|
let sharesArr;
|
|
|
|
try {
|
|
summonerArr = JSON.parse(taskArgs.summoners);
|
|
lootArr = JSON.parse(taskArgs.loot);
|
|
sharesArr = JSON.parse(taskArgs.shares);
|
|
} catch (err) {
|
|
throw "loot shares and summoners should be arrays";
|
|
}
|
|
if (
|
|
!Array.isArray(summonerArr) ||
|
|
!Array.isArray(lootArr) ||
|
|
!Array.isArray(sharesArr)
|
|
) {
|
|
throw "loot shares and summoners should be linked arrays";
|
|
}
|
|
if (
|
|
summonerArr.length !== lootArr.length ||
|
|
lootArr.length !== sharesArr.length
|
|
) {
|
|
throw "arrays must be of the same length";
|
|
}
|
|
|
|
const abiCoder = hre.ethers.utils.defaultAbiCoder;
|
|
|
|
const getBaalParams = async function (
|
|
baal: any,
|
|
poster: any,
|
|
config: {
|
|
PROPOSAL_OFFERING: any;
|
|
GRACE_PERIOD_IN_SECONDS: any;
|
|
VOTING_PERIOD_IN_SECONDS: any;
|
|
QUORUM_PERCENT: any;
|
|
SPONSOR_THRESHOLD: any;
|
|
MIN_RETENTION_PERCENT: any;
|
|
MIN_STAKING_PERCENT: any;
|
|
TOKEN_NAME: any;
|
|
TOKEN_SYMBOL: any;
|
|
},
|
|
metadata: [string, string],
|
|
adminConfig: [boolean, boolean],
|
|
shamans: [string[], number[]],
|
|
shares: [string[], number[]],
|
|
loots: [string[], number[]]
|
|
) {
|
|
const governanceConfig = abiCoder.encode(
|
|
["uint32", "uint32", "uint256", "uint256", "uint256", "uint256"],
|
|
[
|
|
config.VOTING_PERIOD_IN_SECONDS,
|
|
config.GRACE_PERIOD_IN_SECONDS,
|
|
config.PROPOSAL_OFFERING,
|
|
config.QUORUM_PERCENT,
|
|
config.SPONSOR_THRESHOLD,
|
|
config.MIN_RETENTION_PERCENT,
|
|
]
|
|
);
|
|
|
|
const setAdminConfig = await baal.interface.encodeFunctionData(
|
|
"setAdminConfig",
|
|
adminConfig
|
|
);
|
|
const setGovernanceConfig = await baal.interface.encodeFunctionData(
|
|
"setGovernanceConfig",
|
|
[governanceConfig]
|
|
);
|
|
const setShaman = await baal.interface.encodeFunctionData(
|
|
"setShamans",
|
|
shamans
|
|
);
|
|
const mintShares = await baal.interface.encodeFunctionData(
|
|
"mintShares",
|
|
shares
|
|
);
|
|
const mintLoot = await baal.interface.encodeFunctionData(
|
|
"mintLoot",
|
|
loots
|
|
);
|
|
const postMetaData = await poster.interface.encodeFunctionData("post", [
|
|
metadataConfig.CONTENT,
|
|
metadataConfig.TAG,
|
|
]);
|
|
const posterFromBaal = await baal.interface.encodeFunctionData(
|
|
"executeAsBaal",
|
|
[poster.address, 0, postMetaData]
|
|
);
|
|
|
|
const initalizationActions = [
|
|
setAdminConfig,
|
|
setGovernanceConfig,
|
|
setShaman,
|
|
mintShares,
|
|
mintLoot,
|
|
posterFromBaal,
|
|
];
|
|
|
|
// const initalizationActionsMulti = encodeMultiAction(
|
|
// multisend,
|
|
// [setAdminConfig, setGovernanceConfig, setGuildTokens, setShaman, mintShares, mintLoot],
|
|
// [baal.address, baal.address, baal.address, baal.address, baal.address, baal.address],
|
|
// [BigNumber.from(0), BigNumber.from(0), BigNumber.from(0), BigNumber.from(0), BigNumber.from(0), BigNumber.from(0)],
|
|
// [0, 0, 0, 0, 0, 0]
|
|
// )
|
|
return {
|
|
initParams: abiCoder.encode(
|
|
["string", "string", "address", "address", "address", "address","string","string"],
|
|
[
|
|
config.TOKEN_NAME,
|
|
config.TOKEN_SYMBOL,
|
|
zeroAddress,
|
|
zeroAddress,
|
|
zeroAddress,
|
|
zeroAddress,
|
|
]
|
|
),
|
|
initalizationActions,
|
|
};
|
|
};
|
|
|
|
let encodedInitParams: {
|
|
initParams: string;
|
|
initalizationActions: string[];
|
|
};
|
|
|
|
const deploymentConfig = {
|
|
GRACE_PERIOD_IN_SECONDS: 300,
|
|
VOTING_PERIOD_IN_SECONDS: 200,
|
|
PROPOSAL_OFFERING: 0,
|
|
SPONSOR_THRESHOLD: 1,
|
|
MIN_RETENTION_PERCENT: 0,
|
|
MIN_STAKING_PERCENT: 0,
|
|
QUORUM_PERCENT: 0,
|
|
TOKEN_NAME: "Baal Shares",
|
|
TOKEN_SYMBOL: taskArgs.name,
|
|
};
|
|
|
|
const baalSummoner = await hre.ethers.getContractFactory("BaalSummoner");
|
|
const contract = baalSummoner.attach(taskArgs.factory);
|
|
|
|
const baalTemplateAddr = await contract.template();
|
|
console.log("baalTemplateAddr", baalTemplateAddr);
|
|
|
|
const posterFactory = await hre.ethers.getContractFactory("Poster");
|
|
const posterAddress = _addresses.poster;
|
|
console.log("posterAddress", posterAddress);
|
|
|
|
const poster = posterFactory.attach(posterAddress);
|
|
console.log("**********************");
|
|
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baalSingleton = Baal.attach(baalTemplateAddr);
|
|
const MultisendContract = await hre.ethers.getContractFactory("MultiSend");
|
|
const multisend = MultisendContract.attach(
|
|
_addresses.gnosisMultisendLibrary
|
|
);
|
|
|
|
encodedInitParams = await getBaalParams(
|
|
baalSingleton,
|
|
poster,
|
|
deploymentConfig,
|
|
[metadataConfig.CONTENT, metadataConfig.TAG],
|
|
[taskArgs.sharesPaused, taskArgs.lootPaused],
|
|
[[taskArgs.shaman], [7]],
|
|
[summonerArr, sharesArr],
|
|
[summonerArr, lootArr]
|
|
);
|
|
|
|
const randomSeed = Math.floor(Math.random() * 10000000);
|
|
let tx;
|
|
if(taskArgs.withsidecar){
|
|
const baalVaultSummoner = await hre.ethers.getContractFactory("BaalAndVaultSummoner");
|
|
const contractVault = baalVaultSummoner.attach(taskArgs.withsidecar);
|
|
console.log("summon ball and vault from tasks");
|
|
|
|
tx = await contractVault.summonBaalAndVault(
|
|
encodedInitParams.initParams,
|
|
encodedInitParams.initalizationActions,
|
|
randomSeed,
|
|
hre.ethers.utils.formatBytes32String("daohausCLI"),
|
|
"test cli vault"
|
|
);
|
|
} else {
|
|
console.log("summon ball from tasks");
|
|
|
|
tx = await contract.summonBaalFromReferrer(
|
|
encodedInitParams.initParams,
|
|
encodedInitParams.initalizationActions,
|
|
randomSeed,
|
|
hre.ethers.utils.formatBytes32String("daohausCLI")
|
|
);
|
|
}
|
|
|
|
console.log(taskArgs);
|
|
console.log("tx:", tx.hash);
|
|
const deployers = await hre.ethers.getSigners();
|
|
const address = await deployers[0].getAddress();
|
|
const balance = await deployers[0].getBalance();
|
|
console.log("Account address:", address);
|
|
console.log("Account balance:", hre.ethers.utils.formatEther(balance));
|
|
});
|
|
|
|
|
|
/* example:
|
|
npx hardhat summonAdvToken --factory 0x68aA3E7389AC60563dE2fBdCCa06Df79e011043A
|
|
--summoners [\"0xCED608Aa29bB92185D9b6340Adcbfa263DAe075b\",\"0x83ab8e31df35aa3281d630529c6f4bf5ac7f7abf\"]
|
|
--shares [\"10000000000000000000\", \"10000000000000000000\"] --loot [\"10000000000000000000\"]
|
|
--sharespaused false --lootpaused false
|
|
--name gB447 --lootname gb447L007 --network goerli
|
|
*/
|
|
task("baal:summon-advToken", "Summons a new DAO from Higher order factory")
|
|
.addParam("factory", "Dao factory address")
|
|
.addParam(
|
|
"summoners",
|
|
'the summoner addresses (array) (escape quotes) (no spaces) ex [\\"0x123...\\"]'
|
|
)
|
|
.addParam(
|
|
"shares",
|
|
"numnber of initial shares for summoners (string array, escape quotes)"
|
|
)
|
|
.addParam(
|
|
"loot",
|
|
"numnber of initial loot for summoners (string array, escape quotes)"
|
|
)
|
|
.addParam("sharespaused", "are shares transferable")
|
|
.addParam("lootpaused", "is loot transferable")
|
|
.addParam("name", "share token symbol")
|
|
.addParam("lootname", "loot token symbol")
|
|
.addOptionalParam("meta", "updated meta data")
|
|
.setAction(async (taskArgs, hre) => {
|
|
const { deployments, getChainId, network } = hre;
|
|
const chainId = await getChainId();
|
|
const _addresses = {
|
|
...await getSetupAddresses(chainId, network, deployments),
|
|
baalDefaultSingleton: network.name === 'hardhat'
|
|
? (await deployments.get('Baal'))?.address
|
|
: currentDeployments[0]['v103'][network.name as SupportedNetwork]?.addresses?.baalSingleton
|
|
}
|
|
const zeroAddress = ethers.constants.AddressZero;
|
|
const metadataConfig = {
|
|
CONTENT: taskArgs.meta || '{"name":"test"}',
|
|
TAG: "daohaus.summoner.daoProfile",
|
|
};
|
|
let summonerArr;
|
|
let lootArr;
|
|
let sharesArr;
|
|
|
|
try {
|
|
summonerArr = JSON.parse(taskArgs.summoners);
|
|
lootArr = JSON.parse(taskArgs.loot);
|
|
sharesArr = JSON.parse(taskArgs.shares);
|
|
} catch (err) {
|
|
throw "loot shares and summoners should be arrays";
|
|
}
|
|
if (
|
|
!Array.isArray(summonerArr) ||
|
|
!Array.isArray(lootArr) ||
|
|
!Array.isArray(sharesArr)
|
|
) {
|
|
throw "loot shares and summoners should be linked arrays";
|
|
}
|
|
if (
|
|
summonerArr.length !== lootArr.length ||
|
|
lootArr.length !== sharesArr.length
|
|
) {
|
|
throw "arrays must be of the same length";
|
|
}
|
|
|
|
const abiCoder = hre.ethers.utils.defaultAbiCoder;
|
|
|
|
const getBaalParams = async function (
|
|
baal: any,
|
|
config: {
|
|
PROPOSAL_OFFERING: any;
|
|
GRACE_PERIOD_IN_SECONDS: any;
|
|
VOTING_PERIOD_IN_SECONDS: any;
|
|
QUORUM_PERCENT: any;
|
|
SPONSOR_THRESHOLD: any;
|
|
MIN_RETENTION_PERCENT: any;
|
|
MIN_STAKING_PERCENT: any;
|
|
TOKEN_NAME: any;
|
|
TOKEN_SYMBOL: any;
|
|
LOOT_TOKEN_NAME: any;
|
|
LOOT_TOKEN_SYMBOL: any;
|
|
LOOT_TOKEN_TRANSFERABLE: any;
|
|
TOKEN_TRANSFERABLE: any;
|
|
}
|
|
) {
|
|
const governanceConfig = abiCoder.encode(
|
|
["uint32", "uint32", "uint256", "uint256", "uint256", "uint256"],
|
|
[
|
|
config.VOTING_PERIOD_IN_SECONDS,
|
|
config.GRACE_PERIOD_IN_SECONDS,
|
|
config.PROPOSAL_OFFERING,
|
|
config.QUORUM_PERCENT,
|
|
config.SPONSOR_THRESHOLD,
|
|
config.MIN_RETENTION_PERCENT,
|
|
]
|
|
);
|
|
|
|
const metadataConfig = {
|
|
CONTENT: taskArgs.meta || '{"name":"test proposal"}',
|
|
TAG: "daohaus.proposal.metadata",
|
|
};
|
|
|
|
const setGovernanceConfig = await baal.interface.encodeFunctionData(
|
|
"setGovernanceConfig",
|
|
[governanceConfig]
|
|
);
|
|
|
|
const postMetaData = poster.interface.encodeFunctionData("post", [
|
|
metadataConfig.CONTENT,
|
|
metadataConfig.TAG,
|
|
]);
|
|
const posterFromBaal = await baal.interface.encodeFunctionData(
|
|
"executeAsBaal",
|
|
[poster.address, 0, postMetaData]
|
|
);
|
|
|
|
const initalizationActions = [
|
|
setGovernanceConfig,
|
|
posterFromBaal
|
|
];
|
|
|
|
|
|
return {
|
|
initParams: abiCoder.encode(
|
|
["string", "string", "string", "string", "bool", "bool"],
|
|
[
|
|
config.TOKEN_NAME,
|
|
config.TOKEN_SYMBOL,
|
|
config.LOOT_TOKEN_NAME,
|
|
config.LOOT_TOKEN_SYMBOL,
|
|
config.LOOT_TOKEN_TRANSFERABLE,
|
|
config.TOKEN_TRANSFERABLE,
|
|
]
|
|
),
|
|
initalizationActions,
|
|
};
|
|
};
|
|
|
|
let encodedInitParams: {
|
|
initParams: string;
|
|
initalizationActions: string[];
|
|
};
|
|
|
|
const deploymentConfig = {
|
|
GRACE_PERIOD_IN_SECONDS: 300,
|
|
VOTING_PERIOD_IN_SECONDS: 200,
|
|
PROPOSAL_OFFERING: 0,
|
|
SPONSOR_THRESHOLD: 1,
|
|
MIN_RETENTION_PERCENT: 0,
|
|
MIN_STAKING_PERCENT: 0,
|
|
QUORUM_PERCENT: 0,
|
|
TOKEN_NAME: "Baal Shares",
|
|
TOKEN_SYMBOL: taskArgs.name,
|
|
LOOT_TOKEN_NAME: "Baal CUST Loot",
|
|
LOOT_TOKEN_SYMBOL: taskArgs.lootname,
|
|
LOOT_TOKEN_TRANSFERABLE: taskArgs.lootpaused,
|
|
TOKEN_TRANSFERABLE: taskArgs.sharespaused,
|
|
};
|
|
|
|
|
|
const baalSummoner = await hre.ethers.getContractFactory("BaalAdvTokenSummoner");
|
|
const contract = baalSummoner.attach(taskArgs.factory);
|
|
|
|
const posterFactory = await hre.ethers.getContractFactory("Poster");
|
|
const posterAddress = _addresses.poster;
|
|
console.log("posterAddress", posterAddress);
|
|
|
|
const poster = posterFactory.attach(posterAddress);
|
|
console.log("**********************");
|
|
|
|
const Baal = await hre.ethers.getContractFactory("Baal");
|
|
const baalSingleton = Baal.attach(_addresses.baalDefaultSingleton);
|
|
const MultisendContract = await hre.ethers.getContractFactory("MultiSend");
|
|
const multisend = MultisendContract.attach(
|
|
_addresses.gnosisMultisendLibrary
|
|
);
|
|
|
|
encodedInitParams = await getBaalParams(
|
|
baalSingleton,
|
|
deploymentConfig
|
|
);
|
|
|
|
const randomSeed = Math.floor(Math.random() * 10000000);
|
|
let tx;
|
|
|
|
console.log("summon ball from tasks", encodedInitParams);
|
|
|
|
tx = await contract.summonBaalFromReferrer(
|
|
zeroAddress,
|
|
zeroAddress,
|
|
randomSeed,
|
|
abiCoder.encode(
|
|
["address[]", "uint256[]", "uint256[]"],
|
|
[
|
|
summonerArr,
|
|
sharesArr,
|
|
lootArr
|
|
]
|
|
),
|
|
encodedInitParams.initParams,
|
|
encodedInitParams.initalizationActions
|
|
);
|
|
|
|
console.log(taskArgs);
|
|
// console.log("tx:", tx?.hash);
|
|
const deployers = await hre.ethers.getSigners();
|
|
const address = await deployers[0].getAddress();
|
|
const balance = await deployers[0].getBalance();
|
|
console.log("Account address:", address);
|
|
console.log("Account balance:", hre.ethers.utils.formatEther(balance));
|
|
}); |