From 9b5031490ef403e76ee649e310cacfe31a64d02d Mon Sep 17 00:00:00 2001 From: Nicholas Addison Date: Tue, 13 Apr 2021 03:55:02 +1000 Subject: [PATCH] Added eject-staker task --- contracts/interfaces/IEjector.sol | 12 +++++ package.json | 4 +- tasks/ops.ts | 83 +++++++++++++++++++++---------- yarn.lock | 7 +++ 4 files changed, 78 insertions(+), 28 deletions(-) create mode 100644 contracts/interfaces/IEjector.sol diff --git a/contracts/interfaces/IEjector.sol b/contracts/interfaces/IEjector.sol new file mode 100644 index 00000000..31699386 --- /dev/null +++ b/contracts/interfaces/IEjector.sol @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: AGPL-3.0-or-later +pragma solidity 0.8.2; + +/** + * @title IEjector + * @dev interface is used for Hardhat task integration + */ +interface IEjector { + function ejectMany(address[] calldata _users) external; + + function votingLockup() view external returns (address); +} diff --git a/package.json b/package.json index 572e8096..f5d6a9bb 100644 --- a/package.json +++ b/package.json @@ -46,6 +46,7 @@ "@typescript-eslint/eslint-plugin": "^4.14.0", "@typescript-eslint/eslint-plugin-tslint": "^4.14.0", "@typescript-eslint/parser": "^4.14.0", + "axios": "^0.21.1", "chai": "^4.2.0", "chalk": "^4.1.0", "csv-parse": "^4.15.0", @@ -85,5 +86,6 @@ "homepage": "https://github.com/mstable/mstable-contracts#readme", "directories": { "test": "test" - } + }, + "dependencies": {} } diff --git a/tasks/ops.ts b/tasks/ops.ts index 27467a74..4e273d57 100644 --- a/tasks/ops.ts +++ b/tasks/ops.ts @@ -1,13 +1,63 @@ -import { Signer } from "ethers" +import axios from "axios" +import { ContractTransaction, Signer } from "ethers" import { task, types } from "hardhat/config" +import { Speed } from "defender-relay-client" import { DefenderRelayProvider, DefenderRelaySigner } from "defender-relay-client/lib/ethers" -import { ISavingsManager, ISavingsManager__factory } from "types/generated" +import { ISavingsManager, ISavingsManager__factory, IEjector__factory } from "types/generated" import { formatUnits } from "@ethersproject/units" import { tokens } from "./utils/tokens" const getSavingsManager = (signer: Signer, contractAddress = "0x9781c4e9b9cc6ac18405891df20ad3566fb6b301"): ISavingsManager => ISavingsManager__factory.connect(contractAddress, signer) +const getDefenderSigner = async (speed: Speed = "safeLow"): Promise => { + if (!process.env.DEFENDER_API_KEY || !process.env.DEFENDER_API_SECRET) { + console.error(`Defender env vars DEFENDER_API_KEY and/or DEFENDER_API_SECRET have not been set`) + process.exit(1) + } + if (!["safeLow", "average", "fast", "fastest"].includes(speed)) { + console.error(`Defender Relay Speed param must be either 'safeLow', 'average', 'fast' or 'fastest'. Not "${speed}"`) + process.exit(2) + } + const credentials = { + apiKey: process.env.DEFENDER_API_KEY, + apiSecret: process.env.DEFENDER_API_SECRET, + } + const provider = new DefenderRelayProvider(credentials) + const signer = new DefenderRelaySigner(credentials, provider, { speed }) + return signer +} + +const logTxDetails = async (tx: ContractTransaction, method: string): Promise => { + console.log(`Send ${method} transaction with hash ${tx.hash} from ${tx.from} with gas price ${tx.gasPrice.toNumber() / 1e9} Gwei`) + const receipt = await tx.wait() + + // Calculate tx cost in Wei + const txCost = receipt.gasUsed.mul(tx.gasPrice) + console.log(`Processed ${method} tx in block ${receipt.blockNumber}, using ${receipt.gasUsed} gas costing ${formatUnits(txCost)} ETH`) +} + +task("eject-stakers", "Ejects expired stakers from Meta staking contract (vMTA)") + .addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "safeLow", types.string) + .setAction(async (taskArgs) => { + const signer = await getDefenderSigner(taskArgs.speed) + + const ejector = IEjector__factory.connect("0x71061E3F432FC5BeE3A6763Cd35F50D3C77A0434", signer) + // TODO check the last time the eject was run + // Check it's been more than 7 days since the last eject has been run + + // get stakers from API + const response = await axios.get("https://api-dot-mstable.appspot.com/stakers") + const stakers = response.data.ejected + + if (stakers.length === 0) { + console.error(`No stakers to eject`) + process.exit(0) + } + const tx = await ejector.ejectMany(stakers) + await logTxDetails(tx, "ejectMany") + }) + task("collect-interest", "Collects and streams interest from platforms") .addParam( "asset", @@ -16,6 +66,7 @@ task("collect-interest", "Collects and streams interest from platforms") types.string, false, ) + .addOptionalParam("speed", "Defender Relayer speed param: 'safeLow' | 'average' | 'fast' | 'fastest'", "safeLow", types.string) .setAction(async (taskArgs) => { const asset = tokens.find((t) => t.symbol === taskArgs.asset) if (!asset) { @@ -23,17 +74,7 @@ task("collect-interest", "Collects and streams interest from platforms") process.exit(1) } - if (!process.env.DEFENDER_API_KEY || !process.env.DEFENDER_API_SECRET) { - console.error(`Defender env vars DEFENDER_API_KEY and/or DEFENDER_API_SECRET have not been set`) - process.exit(1) - } - const credentials = { - apiKey: process.env.DEFENDER_API_KEY, - apiSecret: process.env.DEFENDER_API_SECRET, - } - const provider = new DefenderRelayProvider(credentials) - const signer = new DefenderRelaySigner(credentials, provider, { speed: "safeLow" }) - + const signer = await getDefenderSigner(taskArgs.speed) const savingManager = getSavingsManager(signer) const lastBatchCollected = await savingManager.lastBatchCollected(asset.address) @@ -43,23 +84,11 @@ task("collect-interest", "Collects and streams interest from platforms") const currentEpoc = new Date().getTime() / 1000 if (currentEpoc - lastBatchCollected.toNumber() < 60 * 60 * 6) { console.error(`Can not run again as the last run was less then 6 hours ago`) - process.exit(2) + process.exit(3) } const tx = await savingManager.collectAndStreamInterest(asset.address) - console.log( - `Send collectAndStreamInterest transaction with hash ${tx.hash} from ${tx.from} with gas price ${ - tx.gasPrice.toNumber() / 1e9 - } Gwei`, - ) - const receipt = await tx.wait() - // Calculate tx cost in Wei - const txCost = receipt.gasUsed.mul(tx.gasPrice) - console.log( - `Processed collectAndStreamInterest tx in block ${receipt.blockNumber}, using ${receipt.gasUsed} gas costing ${formatUnits( - txCost, - )} ETH`, - ) + await logTxDetails(tx, "collectAndStreamInterest") }) module.exports = {} diff --git a/yarn.lock b/yarn.lock index d1289ae8..b3fda396 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1441,6 +1441,13 @@ axios@^0.20.0: dependencies: follow-redirects "^1.10.0" +axios@^0.21.1: + version "0.21.1" + resolved "https://registry.yarnpkg.com/axios/-/axios-0.21.1.tgz#22563481962f4d6bde9a76d516ef0e5d3c09b2b8" + integrity sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA== + dependencies: + follow-redirects "^1.10.0" + axobject-query@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/axobject-query/-/axobject-query-2.2.0.tgz#943d47e10c0b704aa42275e20edf3722648989be"