diff --git a/README.md b/README.md index bb8571aa..d6f29583 100644 --- a/README.md +++ b/README.md @@ -305,6 +305,7 @@ yarn hardhat setActionVars --id c010fb76-ea63-409d-9981-69322d27993a yarn hardhat setActionVars --id 127171fd-7b85-497e-8335-fd7907c08386 yarn hardhat setActionVars --id 84b5f134-8351-4402-8f6a-fb4376034bc4 yarn hardhat setActionVars --id ffcfc580-7b0a-42ed-a4f2-3f0a3add9779 --name ONEINCH_API_KEY # Don't forget to run `export ONEINCH_API_KEY=...` first! +yarn hardhat setActionVars --id 89658c5f-3857-4972-bef8-a5e914e13c56 # setPricesEtherFi yarn hardhat setActionVars --id 32dbc67b-89f3-4856-8f3d-ad4dc5a09322 yarn hardhat setActionVars --id 7a0cb2c9-11c2-41dd-bcd0-d7c2dbda6af6 yarn hardhat setActionVars --id a9fc4c86-0506-4809-afbc-93b5e558cb68 @@ -328,6 +329,7 @@ yarn hardhat updateAction --id c010fb76-ea63-409d-9981-69322d27993a --file autoR yarn hardhat updateAction --id 127171fd-7b85-497e-8335-fd7907c08386 --file autoClaimLidoWithdraw yarn hardhat updateAction --id 84b5f134-8351-4402-8f6a-fb4376034bc4 --file collectLidoFees yarn hardhat updateAction --id ffcfc580-7b0a-42ed-a4f2-3f0a3add9779 --file setPrices +yarn hardhat updateAction --id 89658c5f-3857-4972-bef8-a5e914e13c56 --file setPricesEtherFi yarn hardhat updateAction --id 32dbc67b-89f3-4856-8f3d-ad4dc5a09322 --file collectFeesSonic yarn hardhat updateAction --id 7a0cb2c9-11c2-41dd-bcd0-d7c2dbda6af6 --file allocateSonic yarn hardhat updateAction --id a9fc4c86-0506-4809-afbc-93b5e558cb68 --file collectRewardsSonic diff --git a/src/js/actions/rollup.config.cjs b/src/js/actions/rollup.config.cjs index d13282d7..95df6802 100644 --- a/src/js/actions/rollup.config.cjs +++ b/src/js/actions/rollup.config.cjs @@ -52,6 +52,7 @@ const actions = [ "allocateSonic", "collectRewardsSonic", "setPrices", + "setPricesEtherFi", "setOSSiloPriceAction", "allocateLido", "allocateEtherFi", diff --git a/src/js/actions/setPricesEtherFi.js b/src/js/actions/setPricesEtherFi.js new file mode 100644 index 00000000..0fd5d524 --- /dev/null +++ b/src/js/actions/setPricesEtherFi.js @@ -0,0 +1,50 @@ +const { Defender } = require("@openzeppelin/defender-sdk"); +const { ethers } = require("ethers"); + +const { setPrices } = require("../tasks/lidoMorphoPrices"); +const { mainnet } = require("../utils/addresses"); +const armAbi = require("../../abis/EtherFiARM.json"); + +// Entrypoint for the Defender Action +const handler = async (event) => { + // Initialize defender relayer provider and signer + const client = new Defender(event); + const provider = client.relaySigner.getProvider({ ethersVersion: "v6" }); + const signer = await client.relaySigner.getSigner(provider, { + speed: "fastest", + ethersVersion: "v6", + }); + + console.log( + `DEBUG env var in handler before being set: "${process.env.DEBUG}"`, + ); + + // References to contracts + const arm = new ethers.Contract(mainnet.etherfiARM, armAbi, signer); + + try { + await setPrices({ + signer, + arm, + // sellPrice: 0.9998, + // buyPrice: 0.9997, + maxSellPrice: 1.0, + minSellPrice: 0.9998, + maxBuyPrice: 0.9996, + minBuyPrice: 0.9985, + // inch: true, + // curve: true, + kyber: true, + amount: 10, + tolerance: 0.2, + fee: 0.5, + offset: 0.3, + priceOffset: true, + blockTag: "latest", + }); + } catch (error) { + console.error(error); + } +}; + +module.exports = { handler }; diff --git a/src/js/tasks/rewards.js b/src/js/tasks/rewards.js index 8ecb1e6d..18b3c8c2 100644 --- a/src/js/tasks/rewards.js +++ b/src/js/tasks/rewards.js @@ -1,9 +1,35 @@ +const { formatUnits } = require("ethers"); const { parseDeployedAddress } = require("../utils/addressParser"); +const { getMerklRewards } = require("../utils/merkl"); const { logTxDetails } = require("../utils/txLogger"); const log = require("../utils/logger")("task:rewards"); +async function claimMerklRewards(marketVaultAddress, signer) { + const result = await getMerklRewards({ + userAddress: marketVaultAddress, + chainId: 1, + }); + + log( + `${formatUnits(result.amount, 18)} ${result.token} rewards available to claim.`, + ); + + const marketVault = await ethers.getContractAt( + "Abstract4626MarketWrapper", + marketVaultAddress, + signer, + ); + + const tx = await marketVault.merkleClaim( + result.token, + result.amount, + result.proofs, + ); + await logTxDetails(tx, "merkleClaim"); +} + async function collectMorphoRewards({ arm, signer }) { const marketAddress = arm === "Lido" @@ -22,4 +48,4 @@ async function collectMorphoRewards({ arm, signer }) { await logTxDetails(tx, "collectRewards"); } -module.exports = { collectMorphoRewards }; +module.exports = { claimMerklRewards, collectMorphoRewards }; diff --git a/src/js/tasks/tasks.js b/src/js/tasks/tasks.js index b1f40341..ca2520f3 100644 --- a/src/js/tasks/tasks.js +++ b/src/js/tasks/tasks.js @@ -21,7 +21,7 @@ const { harvestRewards, setHarvester, } = require("./sonicHarvest"); -const { collectMorphoRewards } = require("./rewards"); +const { claimMerklRewards, collectMorphoRewards } = require("./rewards"); const { requestLidoWithdrawals, claimLidoWithdrawals } = require("./lidoQueue"); const { requestEtherFiWithdrawals, @@ -1453,3 +1453,24 @@ subtask( task("setOSSiloPrice").setAction(async (_, __, runSuper) => { return runSuper(); }); + +// Merkl Rewards + +subtask("claimMerklRewards", "Claim Merkl rewards for Morpho markets") + .addOptionalParam( + "arm", + "Name of the ARM. eg Lido, Ether.fi or Oeth", + "Lido", + types.string, + ) + .setAction(async ({ arm }) => { + const signer = await getSigner(); + + const armContract = await resolveArmContract(arm); + const marketVaultAddress = await armContract.activeMarket(); + + await claimMerklRewards(marketVaultAddress, signer); + }); +task("claimMerklRewards").setAction(async (_, __, runSuper) => { + return runSuper(); +}); diff --git a/src/js/utils/merkl.js b/src/js/utils/merkl.js new file mode 100644 index 00000000..0a28bbbd --- /dev/null +++ b/src/js/utils/merkl.js @@ -0,0 +1,25 @@ +const axios = require("axios"); + +const MERKL_API_ENDPOINT = "https://api.merkl.xyz/v4"; + +const getMerklRewards = async ({ userAddress, chainId = 1 }) => { + const url = `${MERKL_API_ENDPOINT}/users/${userAddress}/rewards?chainId=${chainId}`; + try { + const response = await axios.get(url); + + return { + amount: response.data[0].rewards[0].amount, + token: response.data[0].rewards[0].token.address, + proofs: response.data[0].rewards[0].proofs, + }; + } catch (err) { + if (err.response) { + console.error("Response data : ", err.response.data); + console.error("Response status: ", err.response.status); + console.error("Response status: ", err.response.statusText); + } + throw Error(`Call to Merkl API failed: ${err.message}`); + } +}; + +module.exports = { getMerklRewards };