tenderly-wizard-v6
Version:
A tool for managing virtual testnets using Tenderly
84 lines (83 loc) ⢠5.4 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.deploySafeV1 = deploySafeV1;
exports.addSafeSigners = addSafeSigners;
exports.removeDeployerAsOwner = removeDeployerAsOwner;
const safe_master_copy_v1_json_1 = __importDefault(require("../contracts/safe_master_copy_v1.json"));
const safe_proxy_factory_v1_json_1 = __importDefault(require("../contracts/safe_proxy_factory_v1.json"));
const colors_1 = __importDefault(require("colors"));
// @ts-ignore
const hardhat_1 = require("hardhat");
const util_1 = require("../utils/util");
const constants_1 = require("../utils/constants");
const ethers_1 = require("ethers");
async function deploySafeV1(chainConfig, saltNonce) {
const [caller] = await hardhat_1.ethers.getSigners();
const safeMaster = new hardhat_1.ethers.Contract(chainConfig.SAFE_MASTER_COPY_ADDR, safe_master_copy_v1_json_1.default, caller);
// In v6, we need to use the function directly for populateTransaction
const initializer = await safeMaster.setup.populateTransaction([caller.address], 1, //threshold
ethers_1.ZeroAddress, // to
"0x", // data
chainConfig.DEFAULT_FALLBACK_HANDLER_ADDRESS, // fallbackHandler
ethers_1.ZeroAddress, // paymentToken
0, // payment
ethers_1.ZeroAddress // paymentReceiver
);
const safeProxyFactory = new hardhat_1.ethers.Contract(chainConfig.SAFE_PROXY_FACTORY_ADDR, safe_proxy_factory_v1_json_1.default, caller);
const txResponse = await safeProxyFactory.createProxyWithNonce(chainConfig.SAFE_MASTER_COPY_ADDR, initializer.data, saltNonce, {
gasLimit: constants_1.GAS_LIMIT,
});
const txReceipt = await txResponse.wait();
// In v6, we need to use logs and check the fragment name
const txData = txReceipt.logs?.find((x) => x.fragment?.name === "ProxyCreation");
const deployedSafeAddress = txData?.args?.proxy;
console.info(colors_1.default.green(`ā
Safe was deployed to ${deployedSafeAddress} `));
return deployedSafeAddress;
}
// adds signers to a safe (only if they are uniquely new signers)
async function addSafeSigners(safeAddr, newOwners, chainConfig) {
const [caller] = await hardhat_1.ethers.getSigners();
const safe = new hardhat_1.ethers.Contract(safeAddr, safe_master_copy_v1_json_1.default, caller);
const currentOwners = await safe.getOwners();
const hasCommonOwner = newOwners.some(newOwner => currentOwners.some(currentOwner => currentOwner.toLowerCase() === newOwner.toLowerCase()));
if (!hasCommonOwner) {
const addOwnersTxs = await Promise.all(newOwners.map(async (owner) => {
// In v6, we use the function directly for populateTransaction
return await safe.addOwnerWithThreshold.populateTransaction(owner, 1);
}));
const metaTxs = (0, util_1.createMultisendTx)(addOwnersTxs, chainConfig.MULTISEND_ADDR);
const signature = (0, util_1.getPreValidatedSignatures)(caller.address);
const addSignersTx = await safe.execTransaction(chainConfig.MULTISEND_ADDR, constants_1.tx.zeroValue, metaTxs.data, constants_1.SAFE_OPERATION_DELEGATECALL, constants_1.tx.avatarTxGas, constants_1.tx.baseGas, constants_1.tx.gasPrice, constants_1.tx.gasToken, constants_1.tx.refundReceiver, signature);
const txReceipt = await addSignersTx.wait();
// In v6, we need to use logs and check the fragment name
const txData = txReceipt.logs?.filter((x) => x.fragment?.name === "AddedOwner");
const ownersAddedFromEvent = txData.map((log) => log.args);
console.info(`\nš New owners added: ${ownersAddedFromEvent.join(", ")} on Safe: ${safeAddr} `);
}
else {
console.info(`No new owners were added to Safe: ${safeAddr} as at least one owner you tried to add is already an owner on this Safe`);
}
}
async function removeDeployerAsOwner(safeAddr, threshold) {
const [caller] = await hardhat_1.ethers.getSigners();
const safe = new hardhat_1.ethers.Contract(safeAddr, safe_master_copy_v1_json_1.default, caller);
const owners = await safe.getOwners();
const isDeployerStillOwner = owners.some(owner => owner.toLowerCase() === caller.address.toLowerCase());
if (isDeployerStillOwner) {
const callerIndex = owners.findIndex(owner => owner === caller.address);
const prevOwnerIndex = (callerIndex - 1 + owners.length) % owners.length;
const prevOwner = owners[prevOwnerIndex];
// In v6, we use the function directly for populateTransaction
const removeOwnersPopTx = await safe.removeOwner.populateTransaction(prevOwner, caller.address, threshold);
const signature = (0, util_1.getPreValidatedSignatures)(caller.address);
const removeTx = await safe.execTransaction(safeAddr, constants_1.tx.zeroValue, removeOwnersPopTx.data, constants_1.tx.operation, constants_1.tx.avatarTxGas, constants_1.tx.baseGas, constants_1.tx.gasPrice, constants_1.tx.gasToken, constants_1.tx.refundReceiver, signature);
await removeTx.wait();
console.info(`\nš Deployer: ${caller.address} was removed as an owner on Safe: ${safeAddr} `);
}
else {
console.info(`Deployer ${caller.address} is not an owner on Safe: ${safeAddr} so we can't remove them as an owner`);
}
}