import { BigNumber } from '@ethersproject/bignumber'; import { formatEther } from '@ethersproject/units'; import { Contract } from '@ethersproject/contracts'; import { Provider } from '@ethersproject/providers'; import { getProvider, Multicaller } from '../../utils'; import { getAddress } from '@ethersproject/address'; export const author = 'andytcf'; export const version = '1.0.0'; const SDSABI = [ 'function balanceOf(address account) external view returns (uint256)', 'function totalSupply() view returns (uint256)' ]; const DebtCacheABI = [ 'function currentDebt() view returns (uint256 debt, bool anyRateIsInvalid)' ]; const calculateSDSValue = async ( provider: Provider, blockTag: number | string, debtCacheAddress: string, sdsAddress: string ) => { const DebtCacheContract = new Contract( debtCacheAddress, DebtCacheABI, provider ); const currentDebt = await DebtCacheContract.currentDebt({ blockTag }); const SDSContract = new Contract(sdsAddress, SDSABI, provider); const totalSupply = await SDSContract.totalSupply({ blockTag }); const value = Number(currentDebt.debt / totalSupply); return value; }; export async function strategy( _space, _network, _provider, _addresses, _options, _snapshot ) { const score: Record<string, number> = {}; const blockTag = typeof _snapshot === 'number' ? _snapshot : 'latest'; const L2BlockTag = typeof _options.L2BlockNumber === 'number' ? _options.L2BlockNumber : 'latest'; const optimismProvider = getProvider('10'); const L1SDSValue = await calculateSDSValue( _provider, _snapshot, _options.L1DebtCache, _options.L1SDS ); const L2SDSValue = await calculateSDSValue( optimismProvider, L2BlockTag, _options.L2DebtCache, _options.L2SDS ); const callL1SDSBalance = new Multicaller(_network, _provider, SDSABI, { blockTag }); for (const walletAddress of _addresses) { callL1SDSBalance.call(walletAddress, _options.L1SDS, 'balanceOf', [ walletAddress ]); } const L1SDSBalances: Record< string, BigNumber > = await callL1SDSBalance.execute(); Object.entries(L1SDSBalances).forEach(([address, balance]) => { score[getAddress(address)] = Number(formatEther(balance)) * L1SDSValue; }); const callL2SDSBalance = new Multicaller('10', optimismProvider, SDSABI, { blockTag: L2BlockTag }); for (const walletAddress of _addresses) { callL2SDSBalance.call(walletAddress, _options.L2SDS, 'balanceOf', [ walletAddress ]); } const L2SDSBalances: Record< string, BigNumber > = await callL2SDSBalance.execute(); Object.entries(L2SDSBalances).forEach(([address, balance]) => { score[getAddress(address)] += Number(formatEther(balance)) * L2SDSValue; }); /** Quadratic Weighting */ if (_options.quadratic) { return Object.fromEntries( Object.entries(score).map(([address, balance]) => [ address, Math.sqrt(balance) ]) ); } else { return score; } }