diff --git a/contracts/v2/core/SharedDepositMinterV2.sol b/contracts/v2/core/SharedDepositMinterV2.sol index ea2c601..9f3ea12 100644 --- a/contracts/v2/core/SharedDepositMinterV2.sol +++ b/contracts/v2/core/SharedDepositMinterV2.sol @@ -31,6 +31,11 @@ import {Address} from "@openzeppelin/contracts/utils/Address.sol"; import {ETH2DepositWithdrawalCredentials} from "../lib/ETH2DepositWithdrawalCredentials.sol"; +/// @title SharedDepositMinterV2 +/// @author ChimeraDefi - chimera_defi@protonmail.com | sharedstake.org +/// @notice Mints LSD tokens for ETH deposited to the contract. Handles the depositing of ETH to the ETH2 deposit contract and validator creation +/// @dev Deployment params: +/// - addresses : [feeCalc, sgeth, wsgeth, gov] contract SharedDepositMinterV2 is AccessControl, Pausable, ReentrancyGuard, ETH2DepositWithdrawalCredentials { /* ========== STATE VARIABLES ========== */ uint256 public adminFee; diff --git a/contracts/v2/core/WithdrawalQueue.sol b/contracts/v2/core/WithdrawalQueue.sol index edba5bd..d2e836c 100644 --- a/contracts/v2/core/WithdrawalQueue.sol +++ b/contracts/v2/core/WithdrawalQueue.sol @@ -35,7 +35,7 @@ import {SharedDepositMinterV2} from "./SharedDepositMinterV2.sol"; * 3. Fulfill any remaining redeemRequests i.e. totalPendingRequest, * for all RedeemRequest events from requestsFulfilled to requestsCreated */ -contract WithdrawalQueue is AccessControl, GranularPause, ReentrancyGuard, FIFOQueue, OperatorSettable { +contract WithdrawalQueue is AccessControl, ReentrancyGuard, GranularPause, FIFOQueue, OperatorSettable { using Address for address payable; struct Request { diff --git a/contracts/v2/periphery/FeeCalc.sol b/contracts/v2/periphery/FeeCalc.sol index 879a739..35a81b8 100644 --- a/contracts/v2/periphery/FeeCalc.sol +++ b/contracts/v2/periphery/FeeCalc.sol @@ -41,7 +41,7 @@ contract FeeCalc is Ownable2Step { config.adminFee = amount; } - function processDeposit(uint256 value, address sender) external view returns (uint256 amt, uint256 fee) { + function processDeposit(uint256 value, address _sender) external view returns (uint256 amt, uint256 fee) { // TODO: semder is currently unsused but can be used later to calculate a fee reduction based on token holdings if (config.chargeOnDeposit) { fee = (value * adminFee) / BIPS; @@ -49,7 +49,7 @@ contract FeeCalc is Ownable2Step { } } - function processWithdraw(uint256 value, address sender) external view returns (uint256 amt, uint256 fee) { + function processWithdraw(uint256 value, address _sender) external view returns (uint256 amt, uint256 fee) { // TODO: semder is currently unsused but can be used later to calculate a fee reduction based on token holdings if (config.refundFeesOnWithdraw) { fee = (value * adminFee) / BIPS; diff --git a/deploy/03_paymentSplitter.ts b/deploy/03_paymentSplitter.ts index 55c3c23..9594ce3 100644 --- a/deploy/03_paymentSplitter.ts +++ b/deploy/03_paymentSplitter.ts @@ -10,7 +10,7 @@ const func: DeployFunction = async hre => { const multiSig = hre.network.tags.hardhat ? accounts.multiSig.address : "0x610c92c70eb55dfeafe8970513d13771da79f2e0"; const splitterAddresses = [accounts.deployer.address, multiSig, wsgEth.target]; - const splitterValues = [6, 3, 31]; + const splitterValues = [60, 30, 910]; // deploy splitter, with 1k total shares. 9% total fees - 6% for deployer, 3% for multisig, 91% for stakers. await deploy(PaymentSplitter__factory, { args: [splitterAddresses, splitterValues], diff --git a/deploy/04_minter.ts b/deploy/04_minter.ts index a745759..26ea69e 100644 --- a/deploy/04_minter.ts +++ b/deploy/04_minter.ts @@ -1,6 +1,6 @@ import {DeployFunction} from "hardhat-deploy/types"; import Ship from "../utils/ship"; -import {SgETH, SgETH__factory, SharedDepositMinterV2__factory, WSGETH, WSGETH__factory} from "../types"; +import {SgETH, SgETH__factory, SharedDepositMinterV2__factory, WSGETH, WSGETH__factory, DepositContract, DepositContract__factory, FeeCalc, FeeCalc__factory} from "../types"; import {ZeroAddress} from "ethers"; const func: DeployFunction = async hre => { @@ -8,6 +8,17 @@ const func: DeployFunction = async hre => { const sgEth = (await connect(SgETH__factory)) as SgETH; const wsgEth = (await connect(WSGETH__factory)) as WSGETH; + const feeCalc = (await connect(FeeCalc__factory)) as FeeCalc; + + let chainId = await hre.getChainId(); + + let depositContractAddr; + if ( chainId != '1') { + let depositContract = (await connect(DepositContract__factory)) as DepositContract; + depositContractAddr = depositContract.target; + } else { + depositContractAddr = "0x00000000219ab540356cBB839Cbe05303d7705Fa"; + } const numValidators = 1000; const adminFee = 0; @@ -19,12 +30,12 @@ const func: DeployFunction = async hre => { // await feeCalc.deployed(); const addresses = [ - ZeroAddress, - //feeCalc.address, // fee splitter + // ZeroAddress, + feeCalc.target, // fee splitter sgEth.target, // sgETH address wsgEth.target, // wsgETH address multiSig, // government address - ZeroAddress, // deposit contract address - can't find deposit contract - using dummy address + depositContractAddr, // deposit contract address - can't find deposit contract - using dummy address ]; const minter = await deploy(SharedDepositMinterV2__factory, { @@ -40,4 +51,4 @@ const func: DeployFunction = async hre => { export default func; func.tags = ["minter"]; -func.dependencies = ["sgEth", "wsgEth"]; +func.dependencies = ["sgEth", "wsgEth", "depositContract", "feeCalc"]; diff --git a/deploy/04a_depositContract.ts b/deploy/04a_depositContract.ts new file mode 100644 index 0000000..6fb00b2 --- /dev/null +++ b/deploy/04a_depositContract.ts @@ -0,0 +1,20 @@ +import {DeployFunction} from "hardhat-deploy/types"; +import Ship from "../utils/ship"; +import {DepositContract__factory} from "../types"; + +/** + * + * This only needs to be deployed on testnets like sepolia which do not have a deposit contract. + * Do not deploy on mainnet + */ +const func: DeployFunction = async hre => { + const {deploy} = await Ship.init(hre); + + const dc = await deploy(DepositContract__factory, { + args: [], + }); +}; + +export default func; +func.tags = ["depositContract"]; +func.dependencies = []; diff --git a/deploy/04b_feeCalc.ts b/deploy/04b_feeCalc.ts new file mode 100644 index 0000000..32ae2f2 --- /dev/null +++ b/deploy/04b_feeCalc.ts @@ -0,0 +1,25 @@ +import {DeployFunction} from "hardhat-deploy/types"; +import Ship from "../utils/ship"; +import {FeeCalc__factory} from "../types"; + +/** + * + * This only needs to be deployed on testnets like sepolia which do not have a deposit contract. + */ +const func: DeployFunction = async hre => { + const {deploy} = await Ship.init(hre); + + const fc = await deploy(FeeCalc__factory, { + args: [{ + adminFee : 10, + exitFee : 0, + refundFeesOnWithdraw : true, + chargeOnDeposit : true, + chargeOnExit : false, + }], + }); +}; + +export default func; +func.tags = ["feeCalc"]; +func.dependencies = []; diff --git a/deploy/06_rewardsReceiver.ts b/deploy/06_rewardsReceiver.ts index 5cbfcca..df9c413 100644 --- a/deploy/06_rewardsReceiver.ts +++ b/deploy/06_rewardsReceiver.ts @@ -3,6 +3,7 @@ import Ship from "../utils/ship"; import { PaymentSplitter, PaymentSplitter__factory, + RewardsReceiver, RewardsReceiver__factory, SgETH, SgETH__factory, @@ -14,6 +15,18 @@ import { WithdrawalQueue__factory, } from "../types"; +function makeWithdrawalCred(params: any) { + // see https://github.com/ethereum/consensus-specs/pull/2149/files & https://github.com/stakewise/contracts/blob/0e51a35e58676491060df84d665e7ebb0e735d17/test/pool/depositDataMerkleRoot.js#L140 + // pubkey is 0x01 + (11 bytes?) 20 0s + eth1 addr 20 bytes (40 characters) ? = final length 66 + // + let withdrawalCredsPrefix = `0x010000000000000000000000`; + let eth1Withdraw = `${withdrawalCredsPrefix}${params.split("x")[1]}`; + console.log(`setWithdrawalCredential ${eth1Withdraw}`); + + return eth1Withdraw; +} + + const func: DeployFunction = async hre => { const {deploy, connect} = await Ship.init(hre); @@ -26,6 +39,9 @@ const func: DeployFunction = async hre => { await deploy(RewardsReceiver__factory, { args: [withdrawalQueue.target, [sgEth.target, wsgEth.target, paymentSplitter.target, minter.target]], }); + + let rr = (await connect(RewardsReceiver__factory)) as RewardsReceiver; + await minter.setWithdrawalCredential(makeWithdrawalCred(rr.target)); }; export default func; diff --git a/hardhat.config.ts b/hardhat.config.ts index 98da11c..d2326ae 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -39,10 +39,15 @@ const MAINNET_PRIVATE_KEY = process.env.MAINNET_PRIVATE_KEY ? process.env.MAINNE const ETHERSCAN_API = process.env.ETHERSCAN_API ? process.env.ETHERSCAN_API : false; const ALCHEMY_SEPOLIA_KEY = process.env.ALCHEMY_SEPOLIA_KEY ? process.env.ALCHEMY_SEPOLIA_KEY : ""; -const SEPOLIA_RPC_URL = `https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_SEPOLIA_KEY}`; +const SEPOLIA_RPC_URL = process.env.SEPOLIA_RPC_URL + ? process.env.SEPOLIA_RPC_URL + : `https://eth-sepolia.g.alchemy.com/v2/${ALCHEMY_SEPOLIA_KEY}`; const SEPOLIA_PRIVATE_KEY = process.env.SEPOLIA_PRIVATE_KEY ? process.env.SEPOLIA_PRIVATE_KEY : GOERLIPK; +const ACTIVE_DEPLOYER_PK = SEPOLIA_PRIVATE_KEY ? SEPOLIA_PRIVATE_KEY : (MAINNET_PRIVATE_KEY ? MAINNET_PRIVATE_KEY : GOERLIPK); +// const ACTIVE_DEPLOYER_PK = GOERLIPK; + // END required user input const path = require("path"); @@ -156,7 +161,7 @@ const config: HardhatUserConfig = { target: "ethers-v6", }, namedAccounts: { - deployer: 0, + deployer: `privatekey://0x${ACTIVE_DEPLOYER_PK}`, multiSig: 1, alice: 3, bob: 4, diff --git a/scripts/v2/1_deploy_minterv2.js b/scripts/v2/1_deploy_minterv2.js index 34e7d4c..ffe3932 100644 --- a/scripts/v2/1_deploy_minterv2.js +++ b/scripts/v2/1_deploy_minterv2.js @@ -37,16 +37,16 @@ async function main() { let wsgETHAddr = dh.addressOf(wsgETH); params.wsgETH = wsgETHAddr; - - await dh.deployContract("FeeCalc", "FeeCalc", [{ - adminFee: 10, - exitFee: 0, - refundFeesOnWithdraw: true, - chargeOnDeposit: true, - chargeOnExit: false - }]); + await dh.deployContract("FeeCalc", "FeeCalc", [ + { + adminFee: 10, + exitFee: 0, + refundFeesOnWithdraw: true, + chargeOnDeposit: true, + chargeOnExit: false, + }, + ]); params.feeCalcAddr = dh.addressOf("FeeCalc"); - await deployMinterV2(dh, params); let minter = dh.addressOf(params.names.minter); @@ -126,14 +126,14 @@ async function main() { // test deposit withdraw flow await dh.e2e(params); -// starting sgeth bal 0.0 -// Deposited Eth, got sgETH: 0.01 0.01 -// new sgETH bal post withdraw 0.0 -// warmed up deposit/withdraw -// starting wsgeth bal 0.0 -// Staked Eth, got wsgETH: 0.01 0.01 -// Unstaked wsgETH, new wsgETH bal: 0.005 -// warmed up stake/unstake + // starting sgeth bal 0.0 + // Deposited Eth, got sgETH: 0.01 0.01 + // new sgETH bal post withdraw 0.0 + // warmed up deposit/withdraw + // starting wsgeth bal 0.0 + // Staked Eth, got wsgETH: 0.01 0.01 + // Unstaked wsgETH, new wsgETH bal: 0.005 + // warmed up stake/unstake } // We recommend this pattern to be able to use async/await everywhere diff --git a/scripts/v2/lib/DeployHelper.js b/scripts/v2/lib/DeployHelper.js index 79cafc7..e973da4 100644 --- a/scripts/v2/lib/DeployHelper.js +++ b/scripts/v2/lib/DeployHelper.js @@ -46,8 +46,8 @@ class DeployHelper extends OnchainActions { if (this.launchNetwork === "sepolia") { // we can get away with less gas on sepolia maybe - // this.overrides.maxFeePerGas = this.overrides.maxFeePerGas / ethers.getUint(10); - // this.overrides.maxPriorityFeePerGas = this.overrides.maxPriorityFeePerGas / ethers.getUint(10); + this.overrides.maxFeePerGas = this.overrides.maxFeePerGas / ethers.getUint(2); + this.overrides.maxPriorityFeePerGas = this.overrides.maxPriorityFeePerGas / ethers.getUint(2); } log(`Using gas settings: ${ethers.formatUnits((this.overrides.maxFeePerGas).toString(), "gwei")} gwei & bribe: ${ethers.formatUnits(this.overrides.maxPriorityFeePerGas, "gwei")} gwei`); diff --git a/scripts/v2/lib/deploy_utils.js b/scripts/v2/lib/deploy_utils.js index 9f5e26d..ec7fc81 100644 --- a/scripts/v2/lib/deploy_utils.js +++ b/scripts/v2/lib/deploy_utils.js @@ -28,7 +28,10 @@ const isMainnet = launchNetwork => { // some behaviours need to be tested with a mainnet fork which behaves the same as mainnet return launchNetwork == "localhost" || launchNetwork == "mainnet"; }; -const _wait = async ms => await new Promise(resolve => setTimeout(resolve, ms)); +const _wait = async ms => { + log(`Waiting ${ms} ms`); + await new Promise(resolve => setTimeout(resolve, ms)); +} const _printOverrides = o => { return { type: 2, @@ -40,6 +43,12 @@ const _printOverrides = o => { const asMill = (n) => n * 1e7; +const defaultGas = { + type: 2, + maxFeePerGas: ethers.parseUnits("25", "gwei"), + maxPriorityFeePerGas: ethers.parseUnits("1", "gwei"), +}; + const _getOverrides = async () => { const overridesForEIP1559 = { type: 2, @@ -64,6 +73,9 @@ const _getOverrides = async () => { gas = await ethers.provider.getFeeData(); mfpg = gas.maxFeePerGas; + // if (mfpg >= defaultGas.maxFeePerGas) { + // gas = defaultGas; + // } console.log("Done waiting for gas resolution; new gas settings: ", ethers.formatUnits(mfpg.toString(), "gwei")); } overridesForEIP1559.maxPriorityFeePerGas = overridesForEIP1559.maxPriorityFeePerGas >= (gas.maxPriorityFeePerGas) @@ -95,6 +107,9 @@ const _estimateDeploymentGasLimit = async (contractDeployTx) => { // const deploymentData = contract.interface.encodeDeploy(cArgs) // const estimatedGas = await ethers.provider.estimateGas({ data: deploymentData }); const estimatedGas = await ethers.provider.estimateGas(contractDeployTx) + log(`Estimated gas for cdtx: ${Object.keys(contractDeployTx).join(' ')} \n ${Object.values(contractDeployTx).join(' ')}`); + log(`Estimated gas: ${Object.keys(estimatedGas).join(' ')} \n ${Object.values(estimatedGas).join(' ')}`); + return estimatedGas; } @@ -109,15 +124,15 @@ const _deployContract = async (name, launchNetwork = false, cArgs = [], cachedOv const overridesForEIP1559 = cachedOverrides ? cachedOverrides : await _getOverrides(); const factory = await ethers.getContractFactory(name); // const factory = await ethers.ContractFactory - let cdtx = await factory.getDeployTransaction(...cArgs, overridesForEIP1559); - let estimate = await _estimateDeploymentGasLimit(cdtx); - - log(` estimate with settings: \n ${Object.keys(estimate).join(' ')} \n ${Object.values(estimate).join(' ')} from ${cdtx}`) + // let cdtx = await factory.getDeployTransaction(...cArgs, overridesForEIP1559); + // let estimate = await _estimateDeploymentGasLimit(cdtx); + // log(` estimate with settings: \n ${Object.keys(estimate).join(' ')} \n ${Object.values(estimate).join(' ')} from ${cdtx}`) // over write our custom gas limit with what the tx should take // overridesForEIP1559.gasLimit = cdtx.gasLimit > 0 && cdtx.gasLimit < overridesForEIP1559.gasLimit ? cdtx.gasLimit : overridesForEIP1559.gasLimit; + // log(` Deploying with settings: \n ${Object.keys(overridesForEIP1559).join(' ')} \n ${Object.values(overridesForEIP1559).join(' ')}`) - log(` Deploying with settings: \n ${Object.keys(overridesForEIP1559).join(' ')} \n ${Object.values(overridesForEIP1559).join(' ')}`) const contract = await factory.deploy(...cArgs, overridesForEIP1559); + await _wait(10000); console.log("deployment done, now to waitForDeployment") await contract.waitForDeployment(); log(`\n waitForDeployment wait for ${name} \n on ${launchNetwork}. `); @@ -142,7 +157,6 @@ const _verifyAll = async (allContracts, launchNetwork) => { let num = 60000; // 60s log(`Waiting ${num} ms to make sure everything has propagated on etherscan`); await _wait(num); - // wait 10s to make sure everything has propagated on etherscan let contractArr = [], verifyAttemtLog = {}; diff --git a/scripts/v2/lib/onchain_actions.js b/scripts/v2/lib/onchain_actions.js new file mode 100644 index 0000000..2f43cfe --- /dev/null +++ b/scripts/v2/lib/onchain_actions.js @@ -0,0 +1,218 @@ +// onchain actions +// Helpers for triggering transactions for deploy/test +class OA { + constructor(dh) { + this.dh = dh; + } + + async deposit(params = { + names: { + minter: 'SharedDepositMinterV2' + } + }, amt) { + let dh = this.dh; + let c = params.names.minter; + await dh.getContract(c).deposit({ value: amt, ...dh.overrides }); + }; + + async withdraw(params = { + names: { + minter: 'SharedDepositMinterV2' + } + }, amt) { + let dh = this.dh; + let c = params.names.minter; + await dh.getContract(c).withdraw(amt, dh.overrides); + }; + + async depositAndStake(params = { + names: { + minter: 'SharedDepositMinterV2' + } + }, amt) { + let dh = this.dh; + let c = params.names.minter; + await dh.getContract(c).depositAndStake({ value: amt, ...dh.overrides }); + }; + + async unstakeAndWithdraw(params = { + names: { + minter: 'SharedDepositMinterV2' + }, + wsgETH: 'addr' + }, amt) { + let dh = this.dh; + let c = params.names.minter; + let wsgeth = await dh.getContractAt(params.names.wsgETH, params.wsgETH); + await wsgeth.approve(dh.addressOf(c), amt); + await dh.getContract(c).unstakeAndWithdraw(amt, dh.address, dh.overrides); + }; + + async getWSGEthBal(params) { + let wsgeth = await this.dh.getContractAt(params.names.wsgETH, params.wsgETH); + let bal = await wsgeth.balanceOf(this.dh.address); + return bal; + } + + async getSGEthBal(params) { + let sgeth = await this.dh.getContractAt("SgETH", params.sgETH); + let bal = await sgeth.balanceOf(this.dh.address); + return bal; + } + + async getSGEthTotal(params) { + let sgeth = await this.dh.getContractAt("SgETH", params.sgETH); + let bal = await sgeth.totalSupply(); + return bal; + } + + async e2e(params = { + names: { + minter: 'SharedDepositMinterV2' + }, + principal: 0 + }) { + params.wsgETH = params.wsgETH?.length > 0 ? params.wsgETH : this.dh.addressOf(params.names.minter) + let amt = params.principal > 0 ? params.principal : this.dh.parseEther("0.01"); + let recv; + + recv = await this.getSGEthBal(params); + console.log("starting sgeth bal", this.dh.formatEther(recv)); + + await this.deposit(params, amt); + + recv = await this.getSGEthBal(params); + console.log("Deposited Eth, got sgETH:", this.dh.formatEther(amt), this.dh.formatEther(recv)); + + await this.withdraw(params, amt); + recv = await this.getSGEthBal(params); + console.log("new sgETH bal post withdraw", this.dh.formatEther(recv)); + console.log("warmed up deposit/withdraw"); + await new Promise(resolve => setTimeout(resolve, 10000)); // avoid upstream timeouts / rate limits + + recv = await this.getWSGEthBal(params); + console.log("starting wsgeth bal", this.dh.formatEther(recv)); + await this.depositAndStake(params, amt); + recv = await this.getWSGEthBal(params); + console.log("Staked Eth, got wsgETH:", this.dh.formatEther(amt), this.dh.formatEther(recv)); + await this.unstakeAndWithdraw(params, amt.toString() / 2); // leave abit int the wsgeth + recv = await this.getWSGEthBal(params); + console.log("Unstaked wsgETH, new wsgETH bal:", this.dh.formatEther(recv)); + console.log("warmed up stake/unstake"); + } + + async deployNonCustodialStakingPipeline(params = { + sgETH: 'addr', + daoFeeSplitterDistro: { + addresses: [], + values: [] + }, + names: { + yd: '', + rewardsReceiver: '', + withdrawals: '', + daoFeeSplitter: '' + } + }) { + let dh = this.dh; + + await dh.deployContract(params.names.daoFeeSplitter, params.names.daoFeeSplitter, [ + params.daoFeeSplitterDistro.addresses, + params.daoFeeSplitterDistro.values, + ]); + params.daoFeeSplitter = dh.addressOf(params.names.daoFeeSplitter); + + await dh.deployContract("Withdrawals", "Withdrawals", [params.sgETH, params.sgETHVirtualPrice]); + params.withdrawals = dh.addressOf("Withdrawals"); + + await dh.deployContract("RewardsReceiver", "RewardsReceiver", [params.withdrawals, [params.sgETH, params.wsgETH, params.daoFeeSplitter, params.minter]]); + params.rewardsReceiver = dh.addressOf("RewardsReceiver"); + + return params; + } + + async transferRewardsRecvrToMultisig(params = { + names: { + rewardsReceiver: '' + }, + rewardsReceiver: '0xaddr', + multisigAddr: '0xaddr' + }) { + let dh = this.dh; + await dh.transferOwnershipToMultisig(params.names.rewardsReceiver) + dh.log(`Ownership for ${params.names.rewardsReceiver} transferred to Multisig at: ${params.multisigAddr}`); + return params; + } + + async transferSgETHToMultisig(params = { + names: { + sgeth: '' + }, + sgeth: '0xaddr', + multisigAddr: '0xaddr' + }) { + let dh = this.dh; + await dh.transferOwnershipToMultisig(params.names.sgETH) + dh.log(`Ownership for ${params.names.sgETH} transferred to Multisig at: ${params.multisigAddr}`); + return params; + } + + async calcSeedRewardAmt(params) { + let total = await getSGEthTotal(params.wsgETH) + // convert total to expected 5% yield + total = this.dh.parseEther(total.toString()) + total = total.dividedBy(20); + // convert from 5% apr to daily + total = total.dividedBy(365); + return total; + } + + async seedRewards(params, amt) { + let dh = this.dh; + amt = this.dh.parseEther(amt); + let rr = await dh.getContractAt(params.names.rewardsReceiver, params.rewardsReceiver) + let daoFeeSplitter = await dh.getContractAt(params.names.daoFeeSplitter, params.daoFeeSplitter) + let wsgETH = await dh.getContractAt(params.names.wsgETH, params.wsgETH); + let pps = await wsgETH.pricePerShare(); + console.log('Initial price per share:', pps.toString() / 1e18); + await rr.work({value: amt}); + + // https://github.com/ethers-io/ethers.js/discussions/2345 + // need to spec full fn sig since OZ contract has 2 release fns + let fnSig = 'release(address,address)'; + await daoFeeSplitter[fnSig](params.sgETH, params.wsgETH) + pps = await wsgETH.pricePerShare(); + console.log("seeded rewards; Amt: ", amt.toString() / 1e18, "Price per share: ", pps.toString() / 1e18) + } + + async depositEth2(params, validators) { + let _make = (validators) => { + let o = { + pubkeys: [], + sigs: [], + ddrs: [] + } + + validators.forEach(v => { + o.pubkeys.push(this.dh.prepend0x(v.pubkey)); + o.sigs.push(this.dh.prepend0x(v.signature)); + o.ddrs.push(this.dh.prepend0x(v.deposit_data_root)); + }); + + return o; + } + + let args = _make(validators); + + let minter = await this.dh.getContractAt(params.names.minter, params.minter); + let bal = await this.dh.getBalance(params.minter); + + await minter.batchDepositToEth2(args.pubkeys, args.sigs, args.ddrs) + + let bal2 = await this.dh.getBalance(params.minter) + + console.log(`Starting Balance: ${bal.toString() / 1e18} \n Ending Balance: ${bal2.toString() / 1e18}`) + } +} + +module.exports = OA; \ No newline at end of file