Skip to content
This repository was archived by the owner on Aug 22, 2025. It is now read-only.
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
13 changes: 13 additions & 0 deletions src/strategies/erc721-contract-call/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# erc721-contract-call

This is a strategy that calls a function on your NFT contract to retrieve the voting power for each token ID owned by an address

Here is an example of parameters:

```json
{
"address": "0x1234567890123456789012345678901234567890", // Your NFT contract address
"symbol": "xSGT",
"decimals": 0
}
```
11 changes: 11 additions & 0 deletions src/strategies/erc721-contract-call/examples.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"name": "xSGT NFT Voting Power Example",
"strategy": {
"name": "xsgt-nft-voting-power",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should be same as strategy name

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

actually the name xsgt-nft-voting-power makes more sense than erc721-contract-call

"params": {
"address": "0x1234567890123456789012345678901234567890",
"symbol": "xSGT",
"decimals": 0
}
}
}
105 changes: 105 additions & 0 deletions src/strategies/erc721-contract-call/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
import { formatUnits } from '@ethersproject/units';

Check failure on line 1 in src/strategies/erc721-contract-call/index.ts

View workflow job for this annotation

GitHub Actions / build_lint (16.10.x)

Only a void function can be called with the 'new' keyword.

Check failure on line 1 in src/strategies/erc721-contract-call/index.ts

View workflow job for this annotation

GitHub Actions / build_lint (16.10.x)

Expected 4-5 arguments, but got 2.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint / tests are failing in this fail, could take a look?

import { getAddress } from '@ethersproject/address';
import { multicall } from '../../utils';

export const author = 'abysnart';
export const version = '1.0.0';
export const name = 'xSGT NFT Voting Power';
export const description = 'Strategy for xSGT NFT where each token ID has a specific voting power';

// Define interfaces
interface StrategyOptions {
address: string;
symbol: string;
decimals: number;
}

type Scores = Record<string, number>;

// Define ABIs for the required calls
const abi = [
// Get all tokens owned by an address
'function tokensOfOwner(address _owner) external view returns (uint256[])',
// Get voting power for a specific token ID
'function getVotingPower(uint256 _tokenId) external view returns (uint256)'
];

export async function strategy(
space: string,
network: string,
provider: any,
addresses: string[],
options: StrategyOptions,
snapshot: number | string
): Promise<Scores> {
const blockTag = typeof snapshot === 'number' ? snapshot : 'latest';
const contractAddress = options.address; // NFT contract address

const scores: Scores = {};
const addressesLowercased = addresses.map(address => address.toLowerCase());

// Initialize scores with 0
addressesLowercased.forEach(address => {
scores[getAddress(address)] = 0;
});

// First, get all token IDs owned by each address
const tokenOwnershipCalls = addresses.map(address => {
return {
target: contractAddress,
params: [address],
name: 'tokensOfOwner'
};
});

const multi = new multicall(provider, network);
const ownershipResponse: any[][] = await multi.call(
network,
provider,
abi,
tokenOwnershipCalls,
{ blockTag }
);

// Prepare calls to get voting power for each token ID
const votingPowerCalls: { target: string; params: string[]; name: string }[] = [];
const addressIndices: number[] = [];

addresses.forEach((address, addrIndex) => {
const tokenIds = ownershipResponse[addrIndex] || [];

// For each token ID owned by this address, prepare a call to get its voting power
tokenIds.forEach((tokenId: any) => {
votingPowerCalls.push({
target: contractAddress,
params: [tokenId.toString()],
name: 'getVotingPower'
});
addressIndices.push(addrIndex);
});
});

if (votingPowerCalls.length === 0) {
return scores;
}

// Make calls to get voting power for each token ID
const votingPowerResponse: any[][] = await multi.call(
abi,
votingPowerCalls,
{ blockTag }
);

// Sum up voting power for each address
votingPowerResponse.forEach((power, index) => {
const addressIndex = addressIndices[index];
const address = getAddress(addresses[addressIndex]);

// Add this token's voting power to the address's total
if (power && power[0]) {
scores[address] += parseFloat(formatUnits(power[0], 0));
}
});

return scores;
}
33 changes: 33 additions & 0 deletions src/strategies/erc721-contract-call/schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$ref": "#/definitions/Strategy",
"definitions": {
"Strategy": {
"title": "xSGT NFT Voting Power",
"type": "object",
"properties": {
"address": {
"type": "string",
"title": "Contract Address",
"description": "The address of the xSGT NFT contract",
"format": "address",
"examples": ["0x1234567890123456789012345678901234567890"]
},
"symbol": {
"type": "string",
"title": "Symbol",
"description": "The symbol of the NFT token",
"examples": ["xSGT"]
},
"decimals": {
"type": "number",
"title": "Decimals",
"description": "The number of decimals for the voting power (typically 0 for NFTs)",
"default": 0
}
},
"required": ["address"],
"additionalProperties": false
}
}
}
Loading