Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[plearn] Add plearn strategy #1357

Merged
merged 18 commits into from
Nov 28, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion src/strategies/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,7 @@ import * as hatsProtocolHatId from './hats-protocol-hat-id';
import * as hatsProtocolHatIds from './hats-protocol-hat-ids';
import * as bubblegumKids from './bubblegum-kids';
import * as clipperStakedSail from './clipper-staked-sail';
import * as plearn from './plearn';

const strategies = {
'cap-voting-power': capVotingPower,
Expand Down Expand Up @@ -960,7 +961,8 @@ const strategies = {
'hats-protocol-hat-id': hatsProtocolHatId,
'hats-protocol-hat-ids': hatsProtocolHatIds,
'bubblegum-kids': bubblegumKids,
'clipper-staked-sail' : clipperStakedSail
'clipper-staked-sail': clipperStakedSail,
plearn
};

Object.keys(strategies).forEach(function (strategyName) {
Expand Down
47 changes: 47 additions & 0 deletions src/strategies/plearn/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Plearn

This is the most common strategy, it returns the balances of the voters for a balances PLN token
in Plearn project(pools, token).

Here is an example of parameters:

```json
[
{
"name": "Example query",
"strategy": {
"name": "plearn",
"params": {
"lockedPoolAddresses": [
{
"address": "0xc38d542326545470a12B06Bf8e315DE55B0B6B46"
},
{
"address": "0x9b45a8eeD3eF6DA3bE222147533Da542aa384006"
}
],
"foundingInvestorPoolAddresses": [],
"pendingWithdrawalAddresses": [
{
"address": "0x7E4e06C81B41284198C0693cd98eb357257Fc3d9"
},
{
"address": "0xC26a3E07D8CCF34195e943C0bb705f206Dd57030"
}
],
"symbol": "PLN",
"address": "0xBe0D3526fc797583Dada3F30BC390013062A048B",
"decimals": 18
}
},
"network": "56",
"addresses": [
"0xE0d54117600e592E7a78C985996d11b8Fb1B69C3",
"0x3C97c372B45cC96Fe73814721ebbE6db02C9D88E",
"0xB6605F98A5562b1AC821Bc5f2B75934239e8c6D6",
"0x8900cCBdC60fD97E3B7c8529A9987F8c0f8A1125"
],
"snapshot": 33739024
}
]
```
38 changes: 38 additions & 0 deletions src/strategies/plearn/examples.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[
{
"name": "Example query",
"strategy": {
"name": "plearn",
"params": {
"lockedPoolAddresses": [
{
"address": "0xc38d542326545470a12B06Bf8e315DE55B0B6B46"
},
{
"address": "0x9b45a8eeD3eF6DA3bE222147533Da542aa384006"
}
],
"foundingInvestorPoolAddresses": [],
"pendingWithdrawalAddresses": [
{
"address": "0x7E4e06C81B41284198C0693cd98eb357257Fc3d9"
},
{
"address": "0xC26a3E07D8CCF34195e943C0bb705f206Dd57030"
}
],
"symbol": "PLN",
"address": "0xBe0D3526fc797583Dada3F30BC390013062A048B",
"decimals": 18
}
},
"network": "56",
"addresses": [
"0xE0d54117600e592E7a78C985996d11b8Fb1B69C3",
"0x3C97c372B45cC96Fe73814721ebbE6db02C9D88E",
"0xB6605F98A5562b1AC821Bc5f2B75934239e8c6D6",
"0x8900cCBdC60fD97E3B7c8529A9987F8c0f8A1125"
],
"snapshot": 33739024
}
]
144 changes: 144 additions & 0 deletions src/strategies/plearn/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
import { Provider } from '@ethersproject/providers';
import { formatUnits } from '@ethersproject/units';
import { BigNumber } from '@ethersproject/bignumber';
import { multicall } from '../../utils';
import { strategy as erc20BalanceOfStrategy } from '../erc20-balance-of';

export const author = 'plearnclub';
export const version = '0.0.1';

const lockedPoolabi = [
'function userInfo(address) view returns (uint256 amount)'
];

const foundingInvestorPoolabi = [
'function userInfo(address) view returns (uint256 initialAmount, uint256 amount)'
];

const pendingWithdrawalabi = [
'function lockedBalances(address user) view returns (uint256 total, uint256 unlockable, uint256 locked, tuple(uint256 amount, uint256 unlockTime)[] lockData)'
];

function transformResults(
res: any[],
addresses: string[],
balanceTransformer: (result: any) => number
): { [address: string]: number } {
return res.reduce((acc: { [address: string]: number }, result, index) => {
const address = addresses[index % addresses.length];
if (!acc[address]) {
acc[address] = 0;
}

const amount = balanceTransformer(result);
acc[address] += amount;
return acc;
}, {});
}

export async function strategy(
space: string,
network: string,
provider: Provider,
addresses: string[],
options: {
lockedPoolAddresses: { address: string }[];
foundingInvestorPoolAddresses: { address: string }[];
pendingWithdrawalAddresses: { address: string }[];
symbol: string;
address: string;
decimals: number;
},
snapshot: number | string
): Promise<{ [address: string]: number }> {
const blockTag = typeof snapshot === 'number' ? snapshot : 'latest';
const score = await erc20BalanceOfStrategy(
space,
network,
provider,
addresses,
options,
snapshot
);

const lockedPoolCalls = options.lockedPoolAddresses.flatMap((item) =>
addresses.map((address) => [
item.address,
'userInfo',
[address],
{ blockTag }
])
);

const foundingInvestorPoolCalls =
options.foundingInvestorPoolAddresses.flatMap((item) =>
addresses.map((address) => [
item.address,
'userInfo',
[address],
{ blockTag }
])
);

const pendingWithdrawalCalls = options.pendingWithdrawalAddresses.flatMap(
(item) =>
addresses.map((address) => [
item.address,
'lockedBalances',
[address],
{ blockTag }
])
);

const [
lockedPoolBalancesRes,
foundingInvestorPoolBalancesRes,
pendingWithdrawalBalancesRes
] = await Promise.all([
multicall(network, provider, lockedPoolabi, lockedPoolCalls, { blockTag }),
multicall(
network,
provider,
foundingInvestorPoolabi,
foundingInvestorPoolCalls,
{ blockTag }
),
multicall(network, provider, pendingWithdrawalabi, pendingWithdrawalCalls, {
blockTag
})
]);

const pf = (amount: BigNumber) =>
parseFloat(formatUnits(amount, options.decimals));

const lockedPoolScore = transformResults(
lockedPoolBalancesRes,
addresses,
(r) => pf(r.amount)
);
const foundingInvestorPoolScore = transformResults(
foundingInvestorPoolBalancesRes,
addresses,
(r) => pf(r.amount)
);
const pendingWithdrawalScore = transformResults(
pendingWithdrawalBalancesRes,
addresses,
(r) => pf(r.total)
);

const finalScore = Object.keys(score).reduce(
(acc: { [address: string]: number }, address) => {
acc[address] = Math.trunc(
score[address] +
(lockedPoolScore[address] || 0) +
(foundingInvestorPoolScore[address] || 0) +
(pendingWithdrawalScore[address] || 0)
);
return acc;
},
{}
);

return finalScore;
}