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

[multidelegation] feat: multidelegation strategy #1181

Open
wants to merge 28 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
026191e
started strategy
ncomerci Apr 12, 2023
5e2e910
testing
ncomerci Apr 12, 2023
c6f8cfa
Merge branch 'master' into feat-multidelegation-strategy
ncomerci May 22, 2023
b59574b
chore: multidelegation wip
1emu May 22, 2023
de6af1a
chore: changed forEach for reduce
ncomerci May 23, 2023
f2a07b8
chore: multidelegation wip
1emu May 24, 2023
8bdfee0
merge delegations tests
ncomerci May 24, 2023
a8796f0
chore: improve performance by using map instead of record
1emu May 24, 2023
e217c5e
chore: reverse delegations WIP
1emu May 24, 2023
ac38451
strategy working
ncomerci May 24, 2023
ca04c5f
fix: empty delegations
ncomerci May 29, 2023
8d40cdb
chore: multidelegation strategy mocks and tests
1emu May 29, 2023
0bb4553
chore: tests and refactors
1emu May 29, 2023
204fb33
chore: use received space in strategy
1emu May 29, 2023
548fa06
chore: add some more multidelegation test cases
1emu May 30, 2023
ab580ef
chore: use pre-generated addresses in tests and examples
1emu May 30, 2023
de6bc79
changed author
ncomerci May 30, 2023
f5a9b22
Merge branch 'feat-multidelegation-strategy' of github.com:ncomerci/s…
ncomerci May 30, 2023
a0a9e88
Merge branch 'master' into feat-multidelegation-strategy
ncomerci May 30, 2023
9c5dcc4
added Readme
ncomerci May 30, 2023
f1912ec
fix: score splitting in multidelegation
ncomerci May 31, 2023
a8ff203
added test cases & addresses refactor
ncomerci May 31, 2023
62c3d92
chore: extract multi delegation env vars
1emu May 31, 2023
1c3150a
chore: update README.md
1emu May 31, 2023
b7a424c
chore: move tests
1emu May 31, 2023
d169269
chore: renames
1emu May 31, 2023
5e6079a
Merge branch 'master' into feat-multidelegation-strategy
ChaituVR Jun 2, 2023
9194203
Merge branch 'master' into feat-multidelegation-strategy
ncomerci Jun 2, 2023
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
2 changes: 2 additions & 0 deletions src/strategies/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -438,6 +438,7 @@ import * as izumiVeiZi from './izumi-veizi';
import * as lqtyProxyStakers from './lqty-proxy-stakers';
import * as echelonWalletPrimeAndCachedKeyGated from './echelon-wallet-prime-and-cached-key-gated';
import * as rdntCapitalVoting from './rdnt-capital-voting';
import * as multidelegation from './multidelegation';
import * as stakedDefiBalance from './staked-defi-balance';
import * as degenzooErc721AnimalsWeighted from './degenzoo-erc721-animals-weighted';
import * as capVotingPower from './cap-voting-power';
Expand Down Expand Up @@ -891,6 +892,7 @@ const strategies = {
'echelon-wallet-prime-and-cached-key-gated':
echelonWalletPrimeAndCachedKeyGated,
'rdnt-capital-voting': rdntCapitalVoting,
multidelegation,
'staked-defi-balance': stakedDefiBalance,
'degenzoo-erc721-animals-weighted': degenzooErc721AnimalsWeighted,
'zunami-pool-gauge-aggregated-balance-of': zunamiPoolGaugeAggregatedBalanceOf,
Expand Down
58 changes: 58 additions & 0 deletions src/strategies/multidelegation/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# multidelegation

If you want to delegate your voting power to multiple wallet addresses, you can do this using the multidelegation strategy. This strategy is based on [delegation strategy](https:/snapshot-labs/snapshot-strategies/tree/master/src/strategies/delegation) with the exception that you can delegate to several addresses at the same time.

If A delegates to B and C, A's score is split equally to B and C.
In case A already has previously delegated with the [delegation strategy](https:/snapshot-labs/snapshot-strategies/tree/master/src/strategies/delegation), this multidelegation strategy will override it.

The multidelegation smart contract is in Polygon, so the gas fee to delegate is way lower 💸.

| Param Name | Description |
| -------------------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------|
| strategies | List of sub strategies to calculate voting power based on delegation |
| delegationSpace (optional) | Get delegations of a particular space (by default it takes delegations of current space) |
| polygonChain (optional) | Indicates the polygon subgraph to be used to fetch delegations. Possible values are `mumbai` and `mainnet` (by default it uses `mumbai`'s subgraph) |

Here is an example of parameters:

```json
{
"name": "Example query",
"strategy": {
"name": "multidelegation",
"params": {
"symbol": "VP (delegated)",
"polygonChain": "mumbai",
"delegationSpace": "1emu.eth",
"strategies": [
{
"name": "erc20-balance-of",
"params": {
"symbol": "WMANA",
"address": "0xfd09cf7cfffa9932e33668311c4777cb9db3c9be",
"decimals": 18
}
},
{
"name": "erc721-with-multiplier",
"params": {
"symbol": "LAND",
"address": "0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d",
"multiplier": 2000
}
}
]
}
},
"network": "1",
"addresses": [
"0x56d0B5eD3D525332F00C9BC938f93598ab16AAA7",
"0x49E4DbfF86a2E5DA27c540c9A9E8D2C3726E278F",
"0xd7539FCdC0aB79a7B688b04387cb128E75cb77Dc",
"0x4757cE43Dc5429B8F1A132DC29eF970E55Ae722B",
"0xC9dA7343583fA8Bb380A6F04A208C612F86C7701",
"0x69ABF813a683391C0ec888351912E14590B56e88"
],
"snapshot": 17380758
}
```
121 changes: 121 additions & 0 deletions src/strategies/multidelegation/examples.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
[
{
"name": "Example query",
"strategy": {
"name": "multidelegation",
"params": {
"symbol": "VP (delegated)",
"polygonChain": "mumbai",
"delegationSpace": "1emu.eth",
"strategies": [
{
"name": "erc20-balance-of",
"params": {
"symbol": "WMANA",
"address": "0xfd09cf7cfffa9932e33668311c4777cb9db3c9be",
"decimals": 18
}
},
{
"name": "erc721-with-multiplier",
"params": {
"symbol": "LAND",
"address": "0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d",
"multiplier": 2000
}
},
{
"name": "decentraland-estate-size",
"params": {
"symbol": "ESTATE",
"address": "0x959e104e1a4db6317fa58f8295f586e1a978c297",
"multiplier": 2000
}
},
{
"name": "multichain",
"params": {
"name": "multichain",
"graphs": {
"137": "https://api.thegraph.com/subgraphs/name/decentraland/blocks-matic-mainnet"
},
"symbol": "MANA",
"strategies": [
{
"name": "erc20-balance-of",
"params": {
"address": "0x0f5d2fb29fb7d3cfee444a200298f468908cc942",
"decimals": 18
},
"network": "1"
},
{
"name": "erc20-balance-of",
"params": {
"address": "0xA1c57f48F0Deb89f569dFbE6E2B7f46D33606fD4",
"decimals": 18
},
"network": "137"
}
]
}
},
{
"name": "erc721-with-multiplier",
"params": {
"symbol": "NAMES",
"address": "0x2a187453064356c898cae034eaed119e1663acb8",
"multiplier": 100
}
},
{
"name": "decentraland-wearable-rarity",
"params": {
"symbol": "WEARABLE",
"collections": [
"0x32b7495895264ac9d0b12d32afd435453458b1c6",
"0xd35147be6401dcb20811f2104c33de8e97ed6818",
"0xc04528c14c8ffd84c7c1fb6719b4a89853035cdd",
"0xc1f4b0eea2bd6690930e6c66efd3e197d620b9c2",
"0xf64dc33a192e056bb5f0e5049356a0498b502d50",
"0xc3af02c0fd486c8e9da5788b915d6fff3f049866"
],
"multipliers": {
"epic": 10,
"rare": 5,
"mythic": 1000,
"uncommon": 1,
"legendary": 100
}
}
},
{
"name": "decentraland-rental-lessors",
"params": {
"symbol": "RENTAL",
"addresses": {
"land": "0xf87e31492faf9a91b02ee0deaad50d51d56d5d4d",
"estate": "0x959e104e1a4db6317fa58f8295f586e1a978c297"
},
"subgraphs": {
"rentals": "https://api.thegraph.com/subgraphs/name/decentraland/rentals-ethereum-mainnet",
"marketplace": "https://api.thegraph.com/subgraphs/name/decentraland/marketplace"
},
"multipliers": { "land": 2000, "estateSize": 2000 }
}
}
]
}
},
"network": "1",
"addresses": [
"0x56d0B5eD3D525332F00C9BC938f93598ab16AAA7",
"0x49E4DbfF86a2E5DA27c540c9A9E8D2C3726E278F",
"0xd7539FCdC0aB79a7B688b04387cb128E75cb77Dc",
"0x4757cE43Dc5429B8F1A132DC29eF970E55Ae722B",
"0xC9dA7343583fA8Bb380A6F04A208C612F86C7701",
"0x69ABF813a683391C0ec888351912E14590B56e88"
],
"snapshot": 17380758
}
]
97 changes: 97 additions & 0 deletions src/strategies/multidelegation/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
import {
getAddressTotalDelegatedScore,
getDelegationAddresses,
getPolygonMultiDelegations,
getSingleDelegations,
mergeDelegations,
reverseDelegations
} from './utils';
import { getScoresDirect } from '../../utils';
import { getAddress } from '@ethersproject/address';

export const author = 'ncomerci';
export const version = '0.1.0';
export const dependOnOtherAddress = true;

const MULTI_DELEGATION_ENV = {
mainnet: { polygonChainId: '137', subgraphUrl: '' },
mumbai: {
polygonChainId: '80001',
subgraphUrl:
'https://api.thegraph.com/subgraphs/name/1emu/multi-delegation-polygon'
}
};

export async function strategy(
space,
network,
provider,
addresses,
options,
snapshot
) {
const delegationSpace = options.delegationSpace || space;
const checksummedAddresses = addresses.map(getAddress);

const multiDelegationEnv =
(options?.polygonChain && MULTI_DELEGATION_ENV[options.polygonChain]) ||
MULTI_DELEGATION_ENV.mumbai;

// Retro compatibility with the one-to-one delegation strategy
const singleDelegationsPromise = getSingleDelegations(
delegationSpace,
network,
checksummedAddresses,
snapshot
);
const multiDelegationsPromise = getPolygonMultiDelegations(
multiDelegationEnv,
network,
snapshot,
provider,
delegationSpace
);

const [singleDelegations, multiDelegations] = await Promise.all([
singleDelegationsPromise,
multiDelegationsPromise
]);

const isSingleDelegationEmpty = singleDelegations.size === 0;
const isMultiDelegationEmpty = multiDelegations.size === 0;

if (isSingleDelegationEmpty && isMultiDelegationEmpty) {
return Object.fromEntries(
checksummedAddresses.map((address) => [address, 0])
);
}

const mergedDelegations = mergeDelegations(
singleDelegations,
multiDelegations
);
const reversedDelegations = reverseDelegations(mergedDelegations);
const delegationAddresses = getDelegationAddresses(reversedDelegations);

const scores = (
await getScoresDirect(
space,
options.strategies || [],
network,
provider,
delegationAddresses,
snapshot
)
).filter((score) => Object.keys(score).length !== 0);

return Object.fromEntries(
checksummedAddresses.map((delegate) => {
return getAddressTotalDelegatedScore(
delegate,
mergedDelegations,
reversedDelegations,
scores
);
})
);
}
Loading