Skip to content

Commit de722c0

Browse files
authored
Create generic /verify-nft-holder/{contract_address} endpoint for verifying NFT holders via discord POST requests. Refactors utils/inventory to use the POST /tokens-for-user-page endpoint. Adds 'chain' and 'limit' to the fetchUserInventory parameters. (#10)
1 parent 85dcb2f commit de722c0

File tree

6 files changed

+67
-23
lines changed

6 files changed

+67
-23
lines changed

serverless.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,10 @@ functions:
9292
- httpApi:
9393
path: /beacon/writ-of-passage/verify
9494
method: post
95+
# /nft-holders/{nft_address}
96+
verifyNftHolders:
97+
handler: src/handlers/nft-holder.verifyNftHolders
98+
events:
99+
- httpApi:
100+
path: /verify-nft-holder/{address}
101+
method: post

src/constants.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,9 @@ module.exports = {
4646
"0x64bfb08217b30b70f287a1b7f0670bdd49f8a13f",
4747
],
4848
"Treasure | Ecofund (arb1)": ["0x482729215aaf99b3199e41125865821ed5a4978a"],
49-
"Treasure | Ecofund (treasure)": ["0x3418e91949e17ac887c2daeaf7f0799ea9f38f22"],
49+
"Treasure | Ecofund (treasure)": [
50+
"0x3418e91949e17ac887c2daeaf7f0799ea9f38f22",
51+
],
5052
"Treasure | Contributor Allocation (arb1)": [
5153
"0x4D3aAA252850EE7C82b299CB5778925BBE92f1fC", // Multisig
5254
"0xfC05C3C2814DFCfD77Bf8F6796dF413D8BE3D346", // Liquifi Escrow Contract"

src/handlers/nft-holder.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
const { hasNft } = require("../services/nft-holder");
2+
const { parseVulcanWallets } = require("../utils/vulcan");
3+
4+
exports.verifyNftHolders = async (event) => {
5+
const { address } = event.pathParameters ?? {};
6+
if (!address) {
7+
return {
8+
success: false,
9+
reason: `'address' was undefined.`,
10+
};
11+
}
12+
const wallets = parseVulcanWallets(event);
13+
console.log(`Querying NFT (${address}) holder status for wallets:`, wallets);
14+
return {
15+
success: await hasNft(address, wallets),
16+
};
17+
};

src/services/beacon.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ exports.hasFoundingCharacter = async (wallets) => {
1616
...wallets.map((wallet) =>
1717
fetchUserInventory({
1818
userAddress: wallet,
19+
chain: "arb",
1920
collectionAddresses: [CONTRACT_BEACON],
2021
})
2122
),
@@ -46,6 +47,7 @@ exports.hasPet = async (wallets) => {
4647
...wallets.map((wallet) =>
4748
fetchUserInventory({
4849
userAddress: wallet,
50+
chain: "arb",
4951
collectionAddresses: [CONTRACT_BEACON],
5052
})
5153
),

src/services/nft-holder.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
const { fetchUserInventory } = require("../utils/inventory");
2+
3+
exports.hasNft = async (address, wallets) => {
4+
const inventories = await Promise.all(
5+
wallets.map((wallet) =>
6+
fetchUserInventory({
7+
userAddress: wallet,
8+
chain: "treasure",
9+
collectionAddresses: [address],
10+
limit: 1,
11+
})
12+
)
13+
);
14+
15+
return inventories.flat().length > 0;
16+
};

src/utils/inventory.js

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,39 +1,39 @@
11
exports.fetchUserInventory = async ({
22
userAddress,
3+
chain,
34
collectionAddresses = [],
45
tokens = [],
56
projection = "collectionAddr,collectionUrlSlug,queryUserQuantityOwned,metadata,image",
7+
limit = undefined,
68
}) => {
7-
const url = new URL("https://trove-api.treasure.lol/tokens-for-user");
8-
url.searchParams.append("userAddress", userAddress);
9-
url.searchParams.append("projection", projection);
10-
if (tokens.length > 0) {
11-
url.searchParams.append(
12-
"ids",
13-
tokens
14-
.map(({ address, tokenId }) => `arb/${address}/${tokenId}`)
15-
.join(",")
16-
);
17-
} else if (collectionAddresses.length > 0) {
18-
url.searchParams.append(
19-
"slugs",
20-
collectionAddresses.map((address) => `arb/${address}`).join(",")
21-
);
22-
}
9+
const url = new URL("https://trove-api.treasure.lol/tokens-for-user-page");
10+
11+
const body = {
12+
userAddress,
13+
projection,
14+
limit,
15+
ids: tokens.length
16+
? tokens.map(({ address, tokenId }) => `${chain}/${address}/${tokenId}`)
17+
: undefined,
18+
slugs: collectionAddresses.length
19+
? collectionAddresses.map((address) => `${chain}/${address}`)
20+
: undefined,
21+
};
2322

2423
const response = await fetch(url, {
25-
headers: {
26-
"X-API-Key": process.env.TROVE_API_KEY,
27-
},
24+
method: "POST",
25+
headers: { "X-API-Key": process.env.TROVE_API_KEY },
26+
body: JSON.stringify(body),
2827
});
28+
2929
const results = await response.json();
30-
if (!Array.isArray(results)) {
30+
if (!results?.tokens || !Array.isArray(results.tokens)) {
3131
throw new Error(
32-
`Error fetching user inventory: ${results?.message ?? "Unknown error"}`
32+
`Error fetching user inventory: ${results?.message ?? results?.errorMessage ?? "Unknown error"}`
3333
);
3434
}
3535

36-
return results
36+
return results.tokens
3737
.map(
3838
({
3939
collectionAddr: address,

0 commit comments

Comments
 (0)