From 09757e92cef7ede2cfa9b276b03529d936444253 Mon Sep 17 00:00:00 2001 From: 0xmDreamy <0xmDreamy@proton.me> Date: Wed, 14 Aug 2024 18:54:38 +0200 Subject: [PATCH] feat(SpellStaking): Add support for Blast and Kava --- DEPLOYMENT.md | 1 + hardhat.config.ts | 6 ++ package.json | 6 +- scripts/create-spell-staking-task.ts | 2 +- utils/constants.ts | 2 + web3-functions/spell-staking/index.ts | 131 ++++++++++++++++---------- 6 files changed, 94 insertions(+), 54 deletions(-) diff --git a/DEPLOYMENT.md b/DEPLOYMENT.md index bd53750..a1041f6 100644 --- a/DEPLOYMENT.md +++ b/DEPLOYMENT.md @@ -6,6 +6,7 @@ | MagicGlp Arbitrum | [task](https://app.gelato.network/functions/task/0x46cdddc42edb01fb462cb22efd2578d22351629689b00434531df2e254665279:42161) | | MagicGlp Avalanche | [task](https://app.gelato.network/functions/task/0x36ee967b80c68152c0af1c69d49ff60f0eb41264f3cebc4dcc8b16843c7038be:43114) | | SpellSwapper | [task](https://app.gelato.network/functions/task/0x9d6f1f55569bf50b6273f4e1b6a75fc64d8cd906d7c401d501f207f19120e3a0:1) | +| SpellStaking Blast | [task](https://app.gelato.network/functions/task/0xd6b36b19af229cc7291882eac23c45741ef962d1f58d9c5b37ef4ff6a5cf12ce:81457) | | Velodrome vOP/USDC | [task](https://app.gelato.network/functions/task/0x1593a557fbbccc9b8c41f175b059eac993a508e9c104036a1bb93f23b1e5d1e1:10) | | WBTC InterestStrategy | [task](https://app.gelato.network/functions/task/0xdbf9b9d3f40c0c5a44fed95d0d8b1a7ec70882f56e5c3f64a67b4963ca144775:1) | | WETH InterestStrategy | [task](https://app.gelato.network/functions/task/0x49b5af6155b652aa036b3cf22f798f14384aa4b124cb9780ac3141389b00e311:1) | diff --git a/hardhat.config.ts b/hardhat.config.ts index fdd673c..7bb653c 100644 --- a/hardhat.config.ts +++ b/hardhat.config.ts @@ -15,6 +15,7 @@ const config = { "ethereum", "avalanche", "arbitrum", + "blast", "fantom", "optimism", "polygon", @@ -49,6 +50,11 @@ const config = { url: "https://arb1.arbitrum.io/rpc", accounts: [PRIVATE_KEY], }, + blast: { + chainId: 81457, + url: "https://rpc.ankr.com/blast ", + accounts: [PRIVATE_KEY], + }, fantom: { chainId: 250, url: "https://rpc2.fantom.network", diff --git a/package.json b/package.json index 227f319..e1c8358 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "url": "https://github.com/Abracadabra-money/web3-functions", "private": false, "scripts": { - "build": "bun run clean && bun run install && npx tsc", + "build": "bun run clean && bun run install && tsc", "clean": "rm -rf dist", "typecheck": "tsc --noEmit", "lint": "biome check", @@ -13,7 +13,7 @@ "lint:ci": "biome ci", "run-task": "concurrently -m 1 \"bun:run-task:*(!run-task:[^:]+:)\"", "create-task:gm": "hardhat run ./scripts/create-gm-task.ts --network ethereum", - "create-task:spell-staking": "killall -9 anvil; hardhat run ./scripts/create-spell-staking-task.ts --network anvil", + "create-task:spell-staking": "hardhat run ./scripts/create-spell-staking-task.ts", "create-task:magiclvl": "hardhat run ./scripts/create-magiclvl-task.ts --network anvil", "create-task:process-locks": "hardhat run ./scripts/create-process-locks-task.ts --network arbitrum", "create-task:spell-swapper": "hardhat run ./scripts/create-spell-swapper-task.ts --network ethereum", @@ -30,7 +30,9 @@ "run-task:spell-staking:mainnet": "hardhat w3f-run spell-staking --logs --network ethereum", "run-task:spell-staking:avalanche": "hardhat w3f-run spell-staking --logs --network avalanche", "run-task:spell-staking:arbitrum": "hardhat w3f-run spell-staking --logs --network arbitrum", + "run-task:spell-staking:blast": "hardhat w3f-run spell-staking --logs --network blast", "run-task:spell-staking:fantom": "hardhat w3f-run spell-staking --logs --network fantom", + "run-task:spell-staking:kava": "hardhat w3f-run spell-staking --logs --network kava", "run-task:gm": "hardhat w3f-run gm --logs --network arbitrum", "run-task:magiclvl": "hardhat w3f-run magiclvl --logs --network bsc", "run-task:process-locks": "concurrently --kill-others-on-fail -m 1 bun:run-task:process-locks:*", diff --git a/scripts/create-spell-staking-task.ts b/scripts/create-spell-staking-task.ts index c5f9ff7..7074c38 100644 --- a/scripts/create-spell-staking-task.ts +++ b/scripts/create-spell-staking-task.ts @@ -48,7 +48,7 @@ const main = async () => { console.log(); } - const ALTCHAIN_IDS = [250, 43114, 42161]; + const ALTCHAIN_IDS = [250, 43114, 42161, 81457] as const; for (const chainId of ALTCHAIN_IDS) { console.log(`Creating ChainId ${chainId} Task`); diff --git a/utils/constants.ts b/utils/constants.ts index c84192d..1ee9276 100644 --- a/utils/constants.ts +++ b/utils/constants.ts @@ -5,3 +5,5 @@ export const ARBITRUM_SPELL = "0x3e6648c5a70a150a88bce65f4ad4d506fe15d2af" as const satisfies Address; export const ARBITRUM_OPS_SAFE = "0xA71A021EF66B03E45E0d85590432DFCfa1b7174C" as const satisfies Address; +export const GELATO_PROXY = + "0x4D0c7842cD6a04f8EDB39883Db7817160DA159C3" as const satisfies Address; diff --git a/web3-functions/spell-staking/index.ts b/web3-functions/spell-staking/index.ts index 148b4c8..71908c4 100644 --- a/web3-functions/spell-staking/index.ts +++ b/web3-functions/spell-staking/index.ts @@ -3,6 +3,7 @@ import { type Web3FunctionContext, } from "@gelatonetwork/web3-functions-sdk"; import { BigNumber, Contract, utils } from "ethers"; +import { GELATO_PROXY } from "../../utils/constants"; import { LZ_CHAIN_IDS } from "../../utils/lz"; import { SimulationUrlBuilder } from "../../utils/tenderly"; @@ -38,8 +39,10 @@ const MSPELL_STAKING_ADDRESSES: { [chainId: number]: string } = { const MIM_ADDRESSES: { [chainId: number]: string } = { 1: "0x99D8a9C45b2ecA8864373A26D1459e3Dff1e17F3", // Ethereum 250: "0x82f0B8B456c1A451378467398982d4834b6829c1", // Fantom + 2222: "0x471EE749bA270eb4c1165B5AD95E614947f6fCeb", // Kava 43114: "0x130966628846BFd36ff31a822705796e8cb8C18D", // Avalanche 42161: "0xFEa7a6a0B346362BF88A9e4A88416B77a57D6c2A", // Arbitrum + 81457: "0x76DA31D7C9CbEAE102aff34D3398bC450c8374c1", // Blast }; const SPELL_ADDRESSES: { [chainId: number]: string } = { 1: "0x090185f2135308BaD17527004364eBcC2D37e5F6", // Ethereum @@ -48,8 +51,13 @@ const SPELL_ADDRESSES: { [chainId: number]: string } = { 42161: "0x3E6648C5a70A150A88bCE65F4aD4d506Fe15d2AF", // Arbitrum }; +const WITHDRAWER_ADDRESS_LEGACY = + "0x2C9f65BD1a501CB406584F5532cE57c28829B131" as const; +const WITHDRAWER_ADDRESS_LATEST = + "0x22d0e6A4e9b658184248f5e0BF89A0D763849544" as const; + const MAINNET_ADDRESSES = { - withdrawer: "0x2C9f65BD1a501CB406584F5532cE57c28829B131", + withdrawer: WITHDRAWER_ADDRESS_LEGACY, distributor: "0x953DAb0e64828972853E7faA45634620A40Fa479", sSpell: "0x26FA3fFFB6EfE8c1E69103aCb4044C26B9A106a9", treasury: "0xDF2C270f610Dc35d8fFDA5B453E74db5471E126B", @@ -80,12 +88,17 @@ Web3Function.onRun(async (context: Web3FunctionContext) => { const WITHDRAWER_INTERFACE = new utils.Interface(WITHDRAWER_ABI); const DISTRIBUTOR_INTERFACE = new utils.Interface(DISTRIBUTOR_ABI); - // same address on all chains - const WITHDRAWER_ADDRESS = "0x2C9f65BD1a501CB406584F5532cE57c28829B131"; + const ALTCHAIN_IDS = [250, 2222, 43114, 42161, 81457] as const; + const CHAIN_IDS = [1, ...ALTCHAIN_IDS] as const; - // supported chains - const ALTCHAIN_IDS = [250, 43114, 42161]; - const CHAIN_IDS = [1, ...ALTCHAIN_IDS]; + const WITHDRAWER_ADDRESS = { + 1: WITHDRAWER_ADDRESS_LEGACY, + 250: WITHDRAWER_ADDRESS_LEGACY, + 2222: WITHDRAWER_ADDRESS_LATEST, + 42161: WITHDRAWER_ADDRESS_LEGACY, + 43114: WITHDRAWER_ADDRESS_LEGACY, + 81457: WITHDRAWER_ADDRESS_LATEST, + } as const satisfies Record<(typeof CHAIN_IDS)[number], string>; ///////////////////////////////////////////////// // Initialization @@ -93,7 +106,7 @@ Web3Function.onRun(async (context: Web3FunctionContext) => { const info: { [chainId: number]: { withdrawer: Contract; - spell: Contract; + spell: Contract | undefined; mSpellStakedAmount: BigNumber; sSpellStakedAmount: BigNumber; }; @@ -103,8 +116,15 @@ Web3Function.onRun(async (context: Web3FunctionContext) => { const provider = multiChainProvider.chainId(chainId); info[chainId] = { - withdrawer: new Contract(WITHDRAWER_ADDRESS, WITHDRAWER_ABI, provider), - spell: new Contract(SPELL_ADDRESSES[chainId], IERC20_ABI, provider), + withdrawer: new Contract( + WITHDRAWER_ADDRESS[chainId], + WITHDRAWER_ABI, + provider, + ), + spell: + SPELL_ADDRESSES[chainId] !== undefined + ? new Contract(SPELL_ADDRESSES[chainId], IERC20_ABI, provider) + : undefined, mSpellStakedAmount: BigNumber.from(0), sSpellStakedAmount: BigNumber.from(0), }; @@ -158,24 +178,27 @@ Web3Function.onRun(async (context: Web3FunctionContext) => { // Fetch staked amounts await Promise.all( CHAIN_IDS.map(async (chainId) => { - // mSPELL staked amount - info[chainId].mSpellStakedAmount = await info[chainId].spell.balanceOf( - MSPELL_STAKING_ADDRESSES[chainId], - ); - - // sSPELL staked amount (mainnet only) - if (chainId === MAINNET_CHAIN_ID) { - info[chainId].sSpellStakedAmount = await info[ - chainId - ].spell.balanceOf(MAINNET_ADDRESSES.sSpell); + const spellContract = info[chainId].spell; + if (spellContract !== undefined) { + // mSPELL staked amount + info[chainId].mSpellStakedAmount = await spellContract.balanceOf( + MSPELL_STAKING_ADDRESSES[chainId], + ); + + // sSPELL staked amount (mainnet only) + if (chainId === MAINNET_CHAIN_ID) { + info[chainId].sSpellStakedAmount = await spellContract.balanceOf( + MAINNET_ADDRESSES.sSpell, + ); + totalSpellStaked = totalSpellStaked.add( + info[chainId].sSpellStakedAmount, + ); + } + totalSpellStaked = totalSpellStaked.add( - info[chainId].sSpellStakedAmount, + info[chainId].mSpellStakedAmount, ); } - - totalSpellStaked = totalSpellStaked.add( - info[chainId].mSpellStakedAmount, - ); }), ); @@ -223,30 +246,32 @@ Web3Function.onRun(async (context: Web3FunctionContext) => { }); // AltChain allocations - for (const chainId in ALTCHAIN_IDS) { - const amountToBridge = mimBalanceInDistributor - .mul(info[ALTCHAIN_IDS[chainId]].mSpellStakedAmount) - .div(totalSpellStaked); - - // Estimate bridging fee - const { fee, gas } = await distributorMainnet.estimateBridgingFee( - amountToBridge.toString(), - LZ_CHAIN_IDS[ALTCHAIN_IDS[chainId]], - MSPELL_STAKING_ADDRESSES[ALTCHAIN_IDS[chainId]], - ); // use default minDstGasLookup - - distributions.push({ - recipient: MSPELL_STAKING_ADDRESSES[ALTCHAIN_IDS[chainId]], - gas: gas.toString(), - lzChainId: LZ_CHAIN_IDS[ALTCHAIN_IDS[chainId]].toString(), - fee: fee.toString(), - amount: amountToBridge.toString(), - }); + for (const chainId of ALTCHAIN_IDS) { + if (info[chainId].spell !== undefined) { + const amountToBridge = mimBalanceInDistributor + .mul(info[chainId].mSpellStakedAmount) + .div(totalSpellStaked); + + // Estimate bridging fee + const { fee, gas } = await distributorMainnet.estimateBridgingFee( + amountToBridge.toString(), + LZ_CHAIN_IDS[chainId], + MSPELL_STAKING_ADDRESSES[chainId], + ); // use default minDstGasLookup + + distributions.push({ + recipient: MSPELL_STAKING_ADDRESSES[chainId], + gas: gas.toString(), + lzChainId: LZ_CHAIN_IDS[chainId].toString(), + fee: fee.toString(), + amount: amountToBridge.toString(), + }); + } } // withdraw callData.push({ - to: WITHDRAWER_ADDRESS, + to: MAINNET_ADDRESSES.withdrawer, data: WITHDRAWER_INTERFACE.encodeFunctionData("withdraw", []), }); @@ -273,13 +298,17 @@ Web3Function.onRun(async (context: Web3FunctionContext) => { // withdraw callData.push({ - to: WITHDRAWER_ADDRESS, + to: WITHDRAWER_ADDRESS[ + gelatoArgs.chainId as keyof typeof WITHDRAWER_ADDRESS + ], data: WITHDRAWER_INTERFACE.encodeFunctionData("withdraw", []), }); // bridge callData.push({ - to: WITHDRAWER_ADDRESS, + to: WITHDRAWER_ADDRESS[ + gelatoArgs.chainId as keyof typeof WITHDRAWER_ADDRESS + ], data: WITHDRAWER_INTERFACE.encodeFunctionData("bridge", [ mimBalanceInDistributor, fee, @@ -318,11 +347,11 @@ Web3Function.onRun(async (context: Web3FunctionContext) => { await storage.set("lastRun", timestamp.toString()); SimulationUrlBuilder.log( - [WITHDRAWER_ADDRESS], - [callData[0].to], - [0], - [callData[0].data], - [gelatoArgs.chainId], + callData.map(() => GELATO_PROXY), + callData.map(({ to }) => to), + callData.map(() => 0), + callData.map(({ data }) => data), + callData.map(() => gelatoArgs.chainId), ); return {