diff --git a/src/strategies/defi-app-voting/README.md b/src/strategies/defi-app-voting/README.md new file mode 100644 index 000000000..019f8f74b --- /dev/null +++ b/src/strategies/defi-app-voting/README.md @@ -0,0 +1,8 @@ +This strategy returns total voting power on Defi App, based on HOME and sHOME + +Here is an example of parameters: + +{ +"lockingContract": "0xC9714F8f036087d801f38C4105194e150d3a1864", +"homeToken": "0x4BfAa776991E85e5f8b1255461cbbd216cFc714f" +} diff --git a/src/strategies/defi-app-voting/examples.json b/src/strategies/defi-app-voting/examples.json new file mode 100644 index 000000000..226ea60c4 --- /dev/null +++ b/src/strategies/defi-app-voting/examples.json @@ -0,0 +1,19 @@ +[ + { + "name": "sHOME - Base", + "strategy": { + "name": "defi-app-voting", + "params": { + "lockingContract": "0xcfb0c58ac2db2269b4a794e615c9f4c559556da0", + "homeToken": "0xc8688a66f2588ff3064e87e9bad666c281d41af3" + } + }, + "network": "8453", + "addresses": [ + "0xFD79F3E5E5641266c46Aa7F19144Ff7F19a637C7", + "0x4011091Dbe57bd4521F598616fe4BB3978ea3005", + "0x2eAA7327e9B5Ff46bc2B7452acE9e44A1528eb84" + ], + "snapshot": 31224505 + } +] \ No newline at end of file diff --git a/src/strategies/defi-app-voting/index.ts b/src/strategies/defi-app-voting/index.ts new file mode 100644 index 000000000..764084b03 --- /dev/null +++ b/src/strategies/defi-app-voting/index.ts @@ -0,0 +1,52 @@ +import { BigNumberish } from '@ethersproject/bignumber'; +import { formatUnits } from '@ethersproject/units'; +import { Multicaller } from '../../utils'; + +export const author = 'JD0x2e'; +export const version = '0.1.2'; + +const mfdAbi = [ + 'function getUserLocks(address) view returns (tuple(uint256 amount, uint256 unlockTime, uint256 multiplier, uint256 duration, uint256 lockCreationTime)[])' +]; + +const erc20Abi = ['function balanceOf(address) view returns (uint256)']; + +const toJsNum = (bn: BigNumberish) => parseFloat(formatUnits(bn)); + +export async function strategy( + space, + network, + provider, + addresses, + options, + snapshot +): Promise> { + const blockTag = typeof snapshot === 'number' ? snapshot : 'latest'; + + const MFD_CONTRACT = options.lockingContract; + const HOME_TOKEN = options.homeToken; + + const locksMulticaller = new Multicaller(network, provider, mfdAbi, { blockTag }); + const homeMulticaller = new Multicaller(network, provider, erc20Abi, { blockTag }); + + addresses.forEach((address) => { + locksMulticaller.call(address, MFD_CONTRACT, 'getUserLocks', [address]); + homeMulticaller.call(address, HOME_TOKEN, 'balanceOf', [address]); + }); + + const [lockResults, homeBalances] = await Promise.all([ + locksMulticaller.execute(), + homeMulticaller.execute() + ]); + + return Object.fromEntries( + addresses.map((address) => { + const locks = lockResults[address] ?? []; + const sHome = locks.reduce((acc, lock) => acc + toJsNum(lock.amount), 0); + const home = toJsNum(homeBalances[address] ?? 0); + + const weightedPower = sHome * 0.8 + home * 0.2; + return [address, weightedPower]; + }) + ); +} diff --git a/src/strategies/index.ts b/src/strategies/index.ts index 3b712e356..36bf57a2a 100644 --- a/src/strategies/index.ts +++ b/src/strategies/index.ts @@ -167,6 +167,7 @@ import * as tombFinance from './tomb-finance'; import * as trancheStakingSLICE from './tranche-staking-slice'; import * as unipoolUniv2Lp from './unipool-univ2-lp'; import * as unipoolXSushi from './unipool-xsushi'; +import * as defiAppVoting from './defi-app-voting'; import * as taraxaDelegation from './taraxa-delegation'; import * as poap from './poap'; import * as poapWithWeight from './poap-with-weight'; @@ -699,6 +700,7 @@ const strategies = { 'loot-character-guilds': lootCharacterGuilds, 'comp-like-votes-inclusive': compLikeVotesInclusive, mstable, + 'defi-app-voting': defiAppVoting, 'hashes-voting': hashesVoting, 'hashflow-vehft': hashflowVeHft, 'aavegotchi-wagmi-guild': aavegotchiWagmiGuild,