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

Updated to read the balance of veNation for the Passport Holder and filter when less than 1.5 #4

Merged
merged 8 commits into from
Nov 25, 2023
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

Calculates voting power using a cooperative model (one person one vote) based on a user's ownership of nation3 passport (_erc721 NFT_). It also takes into account whether the NFT owner delegated his voting power to another account (using the `setSigner` function)

## Requires 1 input parameters:
## Requires 2 input parameters:

**erc20**

The address of veNation tokens contract

**erc721**

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,20 @@
"strategy": {
"name": "nation3-passport-coop-with-delegations",
"params": {
"erc721": "0x3337dac9f251d4e403d6030e18e3cfb6a2cb1333"
"erc721": "0x3337dac9f251d4e403d6030e18e3cfb6a2cb1333",
"erc20": "0xf7def1d2fbda6b74bee7452fdf7894da9201065d"
}
},
"network": "1",
"addresses": [
"0x61c872A66d79d932F9aEE874b397F2D50Ed78326",
"0xEdd000B7Db3cb8931d4E0cb1D0DBe6B947Ceb09A",
"0x47d80912400ef8f8224531EBEB1ce8f2ACf4b75a",
"0x636d65212C815b93B8E5b069f7082169cec851b7",
"0x460AF11e497dc273fC163414943C6fd95d17B1fd",
"0xfafda3727fe0406e50230bf6092be5ded68cd9e9",
"0x79438224Bc21b0E6B45ECF9F8caADfBdB874DedD"
],
"snapshot": 17683972
"snapshot": 18611783
}
]
59 changes: 51 additions & 8 deletions src/strategies/nation3-passport-coop-with-delegations/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { BigNumber } from '@ethersproject/bignumber';
import { BigNumber, BigNumberish } from '@ethersproject/bignumber';
import { Multicaller } from '../../utils';
import { formatUnits } from '@ethersproject/units';

export const author = 'nation3';
export const version = '0.2.0';

const DECIMALS = 18;

const balanceAbi = [
'function balanceOf(address account) external view returns (uint256)'
];

const ownerAbi = ['function ownerOf(uint256 id) public view returns (address)'];

const signerAbi = [
'function signerOf(uint256 id) external view returns (address)'
];
Expand All @@ -23,6 +32,12 @@ export async function strategy(
const erc721SignerCaller = new Multicaller(network, provider, signerAbi, {
blockTag
});
const erc721OwnerCaller = new Multicaller(network, provider, ownerAbi, {
blockTag
});
const erc20BalanceCaller = new Multicaller(network, provider, balanceAbi, {
blockTag
});
const erc721LastTokenIdCaller = new Multicaller(
network,
provider,
Expand All @@ -35,18 +50,46 @@ export async function strategy(
const lastIndex = await erc721LastTokenIdCaller.execute();
const lastTokenId = BigNumber.from(lastIndex.lastTokenId).toNumber();

for (let i = 0; i < lastTokenId; i++) {
for (let i = 1; i < lastTokenId; i++) {
erc721SignerCaller.call(i, options.erc721, 'signerOf', [i]);
erc721OwnerCaller.call(i, options.erc721, 'ownerOf', [i]);
}

const erc721Signers: Record<string, string> =
await erc721SignerCaller.execute();
const [erc721Signers, erc721Owners]: [
Record<string, string>,
Record<string, string>
] = await Promise.all([
erc721SignerCaller.execute(),
erc721OwnerCaller.execute()
]);

const erc721SignersArr = Object.entries(erc721Signers);
const erc721OwnersArr = Object.entries(erc721Owners);

const eligibleAddresses = erc721SignersArr
.map(([, address]) => address)
.filter((address) => addresses.includes(address));
const eligibleAddresses = erc721SignersArr.filter(([, address]) =>
addresses.includes(address)
);

//create a combined tuple
const eligibleSignerOwner: [string, string, string][] = eligibleAddresses.map(
([id, signerAddress]) => {
const owner = erc721OwnersArr.find(([ownerId]) => id === ownerId);
return [id, signerAddress, owner ? owner[1] : '0x0'];
}
);

eligibleSignerOwner.forEach(([, , owner]) =>
erc20BalanceCaller.call(owner, options.erc20, 'balanceOf', [owner])
);

const erc20Balances: Record<string, BigNumberish> =
await erc20BalanceCaller.execute();

//now we have balances, need to check for > 1.5 on all IDs that have voted
const withPower = eligibleSignerOwner.filter(([, , owner]) => {
const balance = erc20Balances[owner] || 0;
return parseFloat(formatUnits(balance, DECIMALS)) > 1.5;
});

return Object.fromEntries(eligibleAddresses.map((value) => [value, 1]));
return Object.fromEntries(withPower.map(([, signer]) => [signer, 1])) || [];
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,14 @@
"title": "Strategy",
"type": "object",
"properties": {
"erc20": {
"type": "string",
"title": "veNation",
"examples": ["e.g. 0xf7def1d2fbda6b74bee7452fdf7894da9201065d"],
"pattern": "^0x[a-fA-F0-9]{40}$",
"minLength": 42,
"maxLength": 42
},
"erc721": {
"type": "string",
"title": "nation3 passport",
Expand All @@ -15,7 +23,7 @@
"maxLength": 42
}
},
"required": ["erc721"],
"required": ["erc20", "erc721"],
"additionalProperties": false
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/strategies/nation3-votes-with-delegations/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ export async function strategy(
const lastIndex = await erc721LastTokenIdCaller.execute();
const lastTokenId = BigNumber.from(lastIndex.lastTokenId).toNumber();

for (let i = 0; i < lastTokenId; i++) {
for (let i = 1; i < lastTokenId; i++) {
erc721SignerCaller.call(i, options.erc721, 'signerOf', [i]);
erc721OwnerCaller.call(i, options.erc721, 'ownerOf', [i]);
}
Expand Down
Loading