Skip to content

Commit

Permalink
Merge branch 'master' into sf-vesting-strategy
Browse files Browse the repository at this point in the history
  • Loading branch information
d10r authored Jan 2, 2025
2 parents e33481b + 7c4e0c9 commit 4ebb435
Show file tree
Hide file tree
Showing 16 changed files with 823 additions and 9 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"@ethersproject/strings": "^5.6.1",
"@ethersproject/units": "^5.6.1",
"@ethersproject/wallet": "^5.6.2",
"@snapshot-labs/snapshot.js": "^0.12.36",
"@snapshot-labs/snapshot.js": "^0.12.40",
"@spruceid/didkit-wasm-node": "^0.2.1",
"@uniswap/sdk-core": "^3.0.1",
"@uniswap/v3-sdk": "^3.9.0",
Expand Down
4 changes: 1 addition & 3 deletions src/strategies/botto-dao-base/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,7 @@ import { Multicaller } from '../../utils';
export const author = 'agustinjch';
export const version = '1.0.0';

const abi = [
'function userStakes(address) external view returns(uint256)'
];
const abi = ['function userStakes(address) external view returns(uint256)'];

export async function strategy(
space,
Expand Down
6 changes: 6 additions & 0 deletions src/strategies/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,7 @@ import * as sdVoteBoostTWAVPV2 from './sd-vote-boost-twavp-v2';
import * as sdVoteBoostTWAVPV3 from './sd-vote-boost-twavp-v3';
import * as sdVoteBoostTWAVPV4 from './sd-vote-boost-twavp-v4';
import * as sdGaugeLessVoteBoost from './sd-gauge-less-vote-boost';
import * as sdGaugeLessVoteBoostCrosschain from './sd-gauge-less-vote-boost-crosschain';
import * as sdVoteBalanceOfTwavpPool from './sdvote-balanceof-twavp-pool';
import * as sdVoteBoostTWAVPVsdToken from './sd-vote-boost-twavp-vsdtoken';
import * as sdVoteBoostTWAVPVCrossChain from './sd-vote-boost-twavp-vsdcrv-crosschain';
Expand Down Expand Up @@ -466,6 +467,8 @@ import * as sacraSubgraph from './sacra-subgraph';
import * as fountainhead from './fountainhead';
import * as naymsStaking from './nayms-staking';
import * as morphoDelegation from './morpho-delegation';
import * as lizcoinStrategy2024 from './lizcoin-strategy-2024';
import * as realt from './realt';
import * as superfluidVesting from './superfluid-vesting';

const strategies = {
Expand Down Expand Up @@ -862,6 +865,7 @@ const strategies = {
'sd-vote-boost-twavp-v3': sdVoteBoostTWAVPV3,
'sd-vote-boost-twavp-v4': sdVoteBoostTWAVPV4,
'sd-gauge-less-vote-boost': sdGaugeLessVoteBoost,
'sd-gauge-less-vote-boost-crosschain': sdGaugeLessVoteBoostCrosschain,
'sdvote-balanceof-twavp-pool': sdVoteBalanceOfTwavpPool,
'sd-vote-boost-twavp-vsdtoken': sdVoteBoostTWAVPVsdToken,
'sd-vote-boost-twavp-vsdcrv-crosschain': sdVoteBoostTWAVPVCrossChain,
Expand Down Expand Up @@ -944,6 +948,8 @@ const strategies = {
fountainhead,
'nayms-staking': naymsStaking,
'morpho-delegation': morphoDelegation,
'lizcoin-strategy-2024': lizcoinStrategy2024,
realt,
'superfluid-vesting': superfluidVesting
};

Expand Down
36 changes: 36 additions & 0 deletions src/strategies/lizcoin-strategy-2024/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
# Lizcoin Voting Strategy 2024
lizcoin-strategy-2024

A voting strategy for Lizard Labs' Lizcoin ERC20 Token (LIZ).

The strategy is based on the quadratic voting formula. The strategy counts only staked and vested tokens – details
follow bellow.

## Eligible $LIZ forms:
* Staked $LIZ
* Staked LP tokens (converted back to their value in $LIZ)
* vLIZ pre-tokens (investors) in a wallet
* veLIZ pre-tokens (team) in a wallet
* ANY position in the pre-token vesting contract, whether it came from vLIZ, veLIZ, or was set manually for e.g. KOLs

## Ineligible $LIZ forms:
* Regular $LIZ or LP tokens in a wallet
* cLIZ tokens in a wallet
* Staking or loot box rewards that are unclaimed

Here is an example of parameters:

```json
{
"lizcoinAddress": "0xAF4144cd943ed5362Fed2BaE6573184659CBe6FF",
"cLIZAddress": "0x0F9dc0c0A46733c8b9a6C2E4850913Ed31d31205",
"vLIZAddress": "0xe20C4edb8440CaDD4001c144B4F38576d1AA3820",
"veLIZAddress": "0xC817C0B518e8Fc98034ad867d679d4f8A284BFBE",
"cLIZConversionRate": 0.01,
"vLIZConversionRate": 0.01,
"veLIZConversionRate": 0.01,
"uniswapV2PoolAddress": "0xD47B93360EAADBA2678c30F64209a42b9800cEE4",
"stakingContractAddress": "0xEf2E841AA9F49cc0E54697A4Afa6361eA24d682F",
"vestingContractAddress": "0x895ecdCAC6431272946Ec615eD368d2f42fC2b44"
}
```
44 changes: 44 additions & 0 deletions src/strategies/lizcoin-strategy-2024/examples.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
[
{
"name": "Example query for Lizcoin Voting Strategy 2024",
"strategy": {
"name": "lizcoin-strategy-2024",
"params": {
"lizcoinAddress": "0xAF4144cd943ed5362Fed2BaE6573184659CBe6FF",
"cLIZAddress": "0x0F9dc0c0A46733c8b9a6C2E4850913Ed31d31205",
"vLIZAddress": "0xe20C4edb8440CaDD4001c144B4F38576d1AA3820",
"veLIZAddress": "0xC817C0B518e8Fc98034ad867d679d4f8A284BFBE",
"cLIZConversionRate": 0.01,
"vLIZConversionRate": 0.01,
"veLIZConversionRate": 0.01,
"uniswapV2PoolAddress": "0xD47B93360EAADBA2678c30F64209a42b9800cEE4",
"stakingContractAddress": "0xEf2E841AA9F49cc0E54697A4Afa6361eA24d682F",
"vestingContractAddress": "0x895ecdCAC6431272946Ec615eD368d2f42fC2b44"
}
},
"network": "1",
"addresses": [
"0xC5015Af75881b4aBed54043B46561ca829EC2468",
"0x11619E71E2B53AF33e1CFEAaab51d4E570aFC299",
"0x922dfB7092BB3A14A1335c843C1760f88A406E99",
"0xAe8513960374736fAe8CBA47e1A2Ae1Cd842e439",
"0xc9b95B403dC5C9E2A8cB6A703A78016A537DBAE3",
"0xAB12253171A0d73df64B115cD43Fe0A32Feb9dAA",
"0x7C175168d76849Aba1EAD344AD30AC94f120a077",
"0xC1305f9Df23799596a12E6C7cCD8D2663B875D61",
"0x601071a8fB7890bAda13E24c6Bf7838e90778A78",
"0xc6184b7e9C896f5035F7A670BBeA5A445fDA6E1C",
"0xf102978E0C95207AD6Ee2d39d18f1e7497d89EAD",
"0xf91D65180d0e5eD3C5a56B9211b6B4b26E24C2d5",
"0xf02b4c61Bb87817690034667186EF9836F4F0898",
"0xdD020966b963FFC7623498dF5B8Ed14b11AF7B2A",
"0x6C6a234D1806F7d0baC872eD49933A6852424467",
"0x3cC31eFcEEFAdC2A86716A3BeE91D1917418E29a",
"0x8f60501dE5b9b01F9EAf1214dbE1924aA97F7fd0",
"0x9B8e8dD9151260c21CB6D7cc59067cd8DF306D58",
"0x17ea92D6FfbAA1c7F6B117c1E9D0c88ABdc8b84C",
"0x38C0039247A31F3939baE65e953612125cB88268"
],
"snapshot": 21428809
}
]
161 changes: 161 additions & 0 deletions src/strategies/lizcoin-strategy-2024/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { BigNumber, BigNumberish } from '@ethersproject/bignumber';
import { StaticJsonRpcProvider } from '@ethersproject/providers';
import { formatUnits } from '@ethersproject/units';
import { Multicaller } from '../../utils';

export const author = 'ethlizards';
export const version = '0.1.0';

const abi = [
'function decimals() external view returns (uint8)',
'function totalSupply() external view returns (uint256)',
'function balanceOf(address account) external view returns (uint256)',
'function sumDepositAmounts(address depositToken, address rewardToken, address accountAddress) external view returns (uint96)',
// TODO: introduce sumVestedAmounts(address holder) function
'function getVestingSchedulesArray(address holder) external view returns (tuple(uint32 startDate, uint32 duration, uint96 amountVested, uint96 amountClaimed)[])'
];

interface Options {
lizcoinAddress: string;
cLIZAddress: string;
vLIZAddress: string;
veLIZAddress: string;
cLIZConversionRate: number;
vLIZConversionRate: number;
veLIZConversionRate: number;
uniswapV2PoolAddress: string;
stakingContractAddress: string;
vestingContractAddress: string;
}

interface VestingSchedule {
startDate: number;
duration: number;
amountVested: BigNumber;
amountClaimed: BigNumber;
}

export async function strategy(
space: string,
network: string,
provider: StaticJsonRpcProvider,
addresses: string[],
options: Options,
snapshot: number | 'latest'
): Promise<Record<string, number>> {
const blockTag = typeof snapshot === 'number' ? snapshot : 'latest';

const multi = new Multicaller(network, provider, abi, { blockTag });

// Fetch decimals for LIZ, vLIZ, veLIZ, and LP
multi.call('lizcoinDecimals', options.lizcoinAddress, 'decimals');
multi.call('vLIZDecimals', options.vLIZAddress, 'decimals');
multi.call('veLIZDecimals', options.veLIZAddress, 'decimals');
multi.call('lpDecimals', options.uniswapV2PoolAddress, 'decimals');
// Fetch LP/LIZ conversion rate
multi.call('lpSupply', options.uniswapV2PoolAddress, 'totalSupply');
multi.call('lpLizcoinBalance', options.lizcoinAddress, 'balanceOf', [
options.uniswapV2PoolAddress
]);

// Fetch balances for LIZ, vLIZ, and veLIZ
addresses.forEach((address: string) => {
// Staked $LIZ
multi.call(
`stakedLIZ_${address}`,
options.stakingContractAddress,
'sumDepositAmounts',
[options.lizcoinAddress, options.lizcoinAddress, address]
);
// Staked LP tokens
multi.call(
`stakedLP_${address}`,
options.stakingContractAddress,
'sumDepositAmounts',
[options.uniswapV2PoolAddress, options.lizcoinAddress, address]
);
// vLIZ pre-tokens (investors) in a wallet
multi.call(`vLIZ_${address}`, options.vLIZAddress, 'balanceOf', [address]);
// veLIZ pre-tokens (team) in a wallet
multi.call(`veLIZ_${address}`, options.veLIZAddress, 'balanceOf', [
address
]);
// ANY position in the pre-token vesting contract, whether it came from vLIZ, veLIZ, or was set manually for e.g. KOLs
multi.call(
`vestingSchedules_${address}`,
options.vestingContractAddress,
'getVestingSchedulesArray',
[address]
);
});

const result: Record<string, BigNumberish> = await multi.execute();

// decimals
const lizcoinDecimals = result['lizcoinDecimals'];
const vLIZDecimals = result['vLIZDecimals'];
const veLIZDecimals = result['veLIZDecimals'];
const lpDecimals = result['lpDecimals'];
// LP/LIZ conversion rate
const lpSupply = parseFloat(formatUnits(result['lpSupply'], lpDecimals));
const lpLizcoinBalance = parseFloat(
formatUnits(result['lpLizcoinBalance'], lpDecimals)
);
const lpLizcoinConvRate = lpSupply / lpLizcoinBalance / 2;

// derive the voting power as an address:number mapping
const votingPower = Object.fromEntries(
addresses.map(function (address) {
// Staked $LIZ
const stakedLizcoinBalance = parseFloat(
formatUnits(result[`stakedLIZ_${address}`], lizcoinDecimals)
);

// Staked LP tokens (converted back to their value in $LIZ)
const stakedLpBalance =
parseFloat(
formatUnits(result[`stakedLP_${address}`], lizcoinDecimals)
) / lpLizcoinConvRate;

// vLIZ pre-tokens (investors) in a wallet (converted to their value in $LIZ)
const vLIZBalance =
parseFloat(formatUnits(result[`vLIZ_${address}`], vLIZDecimals)) /
options.vLIZConversionRate;

// veLIZ pre-tokens (team) in a wallet (converted to their value in $LIZ)
const veLIZBalance =
parseFloat(formatUnits(result[`veLIZ_${address}`], veLIZDecimals)) /
options.veLIZConversionRate;

// ANY position in the pre-token vesting contract, whether it came from vLIZ, veLIZ, or was set manually for e.g. KOLs
const schedules: VestingSchedule[] = result[
`vestingSchedules_${address}`
] as unknown as VestingSchedule[];
const vestedAmountsSum = schedules.reduce(
(accumulator, currentValue) =>
BigNumber.from(accumulator).add(
BigNumber.from(currentValue.amountVested).sub(
BigNumber.from(currentValue.amountClaimed)
)
),
BigNumber.from(0)
);
const vestedLizcoinBalance = parseFloat(
formatUnits(vestedAmountsSum, lizcoinDecimals)
);

// sum all the balances (already converted to LIZ equivalents)
const totalBalance =
stakedLizcoinBalance +
stakedLpBalance +
vLIZBalance +
veLIZBalance +
vestedLizcoinBalance;

// apply the quadratic voting formula and return
return [address, Math.sqrt(totalBalance)];
})
);
// console.log(votingPower);
return votingPower;
}
Loading

0 comments on commit 4ebb435

Please sign in to comment.