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

Add poap-unlock strategy [poap-unlock] #1209

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions src/strategies/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ import * as unipoolSameToken from './unipool-same-token';
import * as unipoolUniv2Lp from './unipool-univ2-lp';
import * as unipoolXSushi from './unipool-xsushi';
import * as poap from './poap';
import * as poapUnlock from './poap-unlock';
import * as poapWithWeight from './poap-with-weight';
import * as poapWithWeightV2 from './poap-with-weight-v2';
import * as uniswapV3 from './uniswap-v3';
Expand Down Expand Up @@ -652,6 +653,7 @@ const strategies = {
'unipool-univ2-lp': unipoolUniv2Lp,
'unipool-xsushi': unipoolXSushi,
poap: poap,
'poap-unlock': poapUnlock,
'poap-with-weight': poapWithWeight,
'poap-with-weight-v2': poapWithWeightV2,
'uniswap-v3': uniswapV3,
Expand Down
14 changes: 14 additions & 0 deletions src/strategies/poap-unlock/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# POAP-unlock (erc721)

Each POAP is implemented as an erc721 with a max supply tokens.

Returns 1 if account owns any tokens. If `eventsIds` is passed, than it returns 1 if account owns tokens where the event id is included in `eventIds`.

Here are some examples of parameters:

```json
{
"symbol": "POAP",
"eventIds": ["1213", "1293"]
}
```
19 changes: 19 additions & 0 deletions src/strategies/poap-unlock/examples.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
[
{
"name": "Example query",
"strategy": {
"name": "poap-unlock",
"params": {
"symbol": "POAP",
"eventIds": ["1213", "1293"]
}
},
"network": "100",
"addresses": [
"0x837d21cfda71e93e5257f95ce2c49751675ebcb1",
"0x00ac36c51500e900ab0f4e692fc1338cf70571b2",
"0xdd6f702c2907ce401888d993d7dc185e7a824466"
],
"snapshot": 25283078
}
]
112 changes: 112 additions & 0 deletions src/strategies/poap-unlock/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { getAddress } from '@ethersproject/address';
import { subgraphRequest } from '../../utils';
import { strategy as erc721Strategy } from '../erc721';

export const author = 'paulperegud';
export const version = '1.0.0';

// subgraph query in filter has max length of 500
const EVENT_IDS_LIMIT = 500;
const POAP_API_ENDPOINT_URL = {
'1': 'https://api.thegraph.com/subgraphs/name/poap-xyz/poap',
'100': 'https://api.thegraph.com/subgraphs/name/poap-xyz/poap-xdai'
};
// subgraph query in filter has max length of 500
const MAX_ACCOUNTS_IN_QUERY = 500;

export async function strategy(
space,
network,
provider,
addresses,
options,
snapshot
) {
const shouldFilterForEvents = (options?.eventIds?.length ?? 0) > 0;

if (!shouldFilterForEvents) {
const results = await erc721Strategy(
space,
network,
provider,
addresses,
{ address: '0x22C1f6050E56d2876009903609a2cC3fEf83B415' },
snapshot
);
return addresses.reduce((map, address) => {
map[getAddress(address)] = results[address] ?? 0;
return map;
}, {});
}

if (shouldFilterForEvents && options.eventIds.length > EVENT_IDS_LIMIT) {
throw new Error(`Max number (${EVENT_IDS_LIMIT}) of event ids exceeded`);
}

const addressesMap = addresses.reduce((map, address) => {
map[getAddress(address)] = 0;
return map;
}, {});
const lowercaseAddresses = Object.keys(addressesMap).map((address) =>
address.toLowerCase()
);

// batch addresses to query into slices of MAX_ACCOUNTS_IN_QUERY size
const lowercaseAddressBatches: string[][] = [];
for (let i = 0; i < lowercaseAddresses.length; i += MAX_ACCOUNTS_IN_QUERY) {
const slice = lowercaseAddresses.slice(i, i + MAX_ACCOUNTS_IN_QUERY);
lowercaseAddressBatches.push(slice);
}

const query = {
accounts: {
__args: {
where: {
id_in: [] as string[]
}
},
id: true,
tokens: {
__args: {
where: {
event_in: options.eventIds
}
},
id: true
}
}
};
if (snapshot !== 'latest') {
query.accounts.__args['block'] = { number: snapshot };
}

const results = await Promise.allSettled<{
accounts: { id: string; tokens?: { id: string }[] }[];
}>(
lowercaseAddressBatches.map((addresses) => {
query.accounts.__args.where.id_in = addresses;
return subgraphRequest(POAP_API_ENDPOINT_URL[network], query);
})
);

for (const supplyResponse of results) {
if (supplyResponse.status === 'rejected') continue;

for (const account of supplyResponse.value.accounts) {
const accountId = getAddress(account.id);

if (addressesMap[accountId] === undefined) continue;

addressesMap[accountId] = account.tokens?.length ?? 0;
}

}

for (let address in addressesMap) {
if (addressesMap[address] > 0) {
addressesMap[address] = 1;
}
}

return addressesMap;
}